summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--.gitmodules7
-rw-r--r--CMakeLists.txt10
-rw-r--r--INSTALL.md61
-rw-r--r--Makefile27
-rw-r--r--README.md6
-rw-r--r--benchmark/util/tilecover.benchmark.cpp96
-rw-r--r--circle.yml9
-rw-r--r--cmake/NodeJS.cmake600
-rw-r--r--cmake/benchmark-files.cmake1
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--cmake/loop-uv.cmake20
-rw-r--r--cmake/mason.cmake8
-rw-r--r--cmake/mbgl.cmake33
-rw-r--r--cmake/node.cmake119
-rw-r--r--cmake/test.cmake5
-rw-r--r--include/mbgl/tile/tile_id.hpp20
-rw-r--r--include/mbgl/util/projection.hpp16
m---------mapbox-gl-js0
-rw-r--r--misc/ca-bundle.crt133
-rw-r--r--package.json2
-rw-r--r--platform/android/CHANGELOG.md23
-rw-r--r--platform/android/MapboxGLAndroidSDK/.gitignore1
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle13
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java74
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java227
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java44
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java103
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java218
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java108
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java34
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java24
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java41
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java83
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java218
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java273
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java47
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java177
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java129
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java79
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java82
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java71
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml3
-rw-r--r--platform/android/README.md11
-rw-r--r--platform/android/build.gradle2
-rw-r--r--platform/android/config.cmake2
-rw-r--r--platform/android/gradle/dependencies.gradle27
-rw-r--r--platform/android/gradle/gradle-dependencies-graph.gradle29
-rw-r--r--platform/android/gradle/wrapper/gradle-wrapper.properties3
-rw-r--r--platform/android/scripts/exclude-activity-gen.json3
-rwxr-xr-xplatform/android/scripts/generate-style-code.js18
-rw-r--r--platform/android/src/bitmap.cpp3
-rw-r--r--platform/android/src/file_source.cpp14
-rw-r--r--platform/android/src/file_source.hpp2
-rw-r--r--platform/android/src/geojson/point.cpp2
-rw-r--r--platform/android/src/run_loop.cpp6
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.cpp12
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.hpp1
-rw-r--r--platform/darwin/docs/guides/Predicates and Expressions.md4
-rwxr-xr-xplatform/darwin/scripts/generate-style-code.js11
-rw-r--r--platform/darwin/src/MGLAccountManager.m4
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm6
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h6
-rw-r--r--platform/darwin/src/MGLCompassDirectionFormatter.m4
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.h4
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.mm6
-rw-r--r--platform/darwin/src/MGLComputedShapeSource_Private.h2
-rw-r--r--platform/darwin/src/MGLFeature.h8
-rw-r--r--platform/darwin/src/MGLFeature.mm6
-rw-r--r--platform/darwin/src/MGLFeature_Private.h4
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h5
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm5
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm8
-rw-r--r--platform/darwin/src/MGLPolygon.h8
-rw-r--r--platform/darwin/src/MGLPolygon.mm8
-rw-r--r--platform/darwin/src/MGLPolygon_Private.h2
-rw-r--r--platform/darwin/src/MGLPolyline.h4
-rw-r--r--platform/darwin/src/MGLPolyline.mm8
-rw-r--r--platform/darwin/src/MGLPolyline_Private.h2
-rw-r--r--platform/darwin/src/MGLRasterTileSource.h2
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm2
-rw-r--r--platform/darwin/src/MGLShapeCollection.h4
-rw-r--r--platform/darwin/src/MGLShapeCollection.mm4
-rw-r--r--platform/darwin/src/MGLShapeSource.h10
-rw-r--r--platform/darwin/src/MGLShapeSource.mm12
-rw-r--r--platform/darwin/src/MGLShapeSource_Private.h2
-rw-r--r--platform/darwin/src/MGLStyle.h6
-rw-r--r--platform/darwin/src/MGLStyle.mm24
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs12
-rw-r--r--platform/darwin/src/MGLStyle_Private.h10
-rw-r--r--platform/darwin/src/MGLTileSource.h15
-rw-r--r--platform/darwin/src/MGLTileSource.mm6
-rw-r--r--platform/darwin/src/MGLTileSource_Private.h4
-rw-r--r--platform/darwin/src/MGLTypes.h20
-rw-r--r--platform/darwin/src/MGLVectorTileSource.h4
-rw-r--r--platform/darwin/src/MGLVectorTileSource.mm8
-rw-r--r--platform/darwin/src/MGLVectorTileSource_Private.h2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.h2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m2
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm17
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm70
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h3
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m33
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m6
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.mm9
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm33
-rw-r--r--platform/darwin/test/MGLCoordinateFormatterTests.m21
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm81
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm6
-rw-r--r--platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLHeatmapStyleLayerTests.mm12
-rw-r--r--platform/darwin/test/MGLHillshadeStyleLayerTests.mm18
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm42
-rw-r--r--platform/darwin/test/MGLNSStringAdditionsTests.m54
-rw-r--r--platform/darwin/test/MGLPredicateTests.mm30
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.h2
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m4
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs14
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm150
-rw-r--r--platform/darwin/test/MGLTestUtility.h27
-rw-r--r--platform/default/mbgl/map/map_snapshotter.cpp15
-rw-r--r--platform/default/mbgl/map/map_snapshotter.hpp2
-rw-r--r--platform/default/mbgl/storage/offline.cpp2
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp587
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp21
-rw-r--r--platform/default/sqlite3.cpp370
-rw-r--r--platform/default/sqlite3.hpp107
-rw-r--r--platform/ios/CHANGELOG.md19
-rw-r--r--platform/ios/DEVELOPING.md6
-rw-r--r--platform/ios/INSTALL.md29
-rw-r--r--platform/ios/Integration Tests/MGLCameraTransitionTests.mm401
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.h14
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.m12
-rw-r--r--platform/ios/Integration Tests/MGLShapeSourceTests.m126
-rw-r--r--platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec4
-rw-r--r--platform/ios/Mapbox-iOS-SDK-static-part.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec4
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec4
-rw-r--r--platform/ios/app/MBXOfflinePacksTableViewController.m6
-rw-r--r--platform/ios/app/MBXViewController.m155
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.mm4
-rw-r--r--platform/ios/docs/doc-README.md2
-rw-r--r--platform/ios/docs/pod-README.md4
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj30
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme17
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/Integration Test Harness.xcscheme2
-rw-r--r--platform/ios/ios.xcworkspace/contents.xcworkspacedata9
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.h2
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.m4
-rw-r--r--platform/ios/src/MGLAnnotationContainerView_Private.h2
-rw-r--r--platform/ios/src/MGLCameraChangeReason.h6
-rw-r--r--platform/ios/src/MGLMapAccessibilityElement.mm6
-rw-r--r--platform/ios/src/MGLMapView.h38
-rw-r--r--platform/ios/src/MGLMapView.mm184
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h2
-rw-r--r--platform/ios/src/MGLScaleBar.mm198
-rw-r--r--platform/ios/src/MGLUserLocation.m2
-rw-r--r--platform/ios/test/MGLAnnotationViewTests.m9
-rw-r--r--platform/ios/test/MGLMapAccessibilityElementTests.m6
-rw-r--r--platform/ios/uitest/.gitignore3
-rw-r--r--platform/ios/uitest/App-Info.plist53
-rw-r--r--platform/ios/uitest/Bundle-Info.plist22
-rw-r--r--platform/ios/uitest/Images.xcassets/AppIcon.appiconset/Contents.json73
-rw-r--r--platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Contents.json53
-rw-r--r--platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.pngbin184 -> 0 bytes
-rw-r--r--platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default@2x.pngbin170 -> 0 bytes
m---------platform/ios/uitest/KIF0
-rw-r--r--platform/ios/uitest/KIFTestActor+MapboxGL.h13
-rw-r--r--platform/ios/uitest/KIFTestActor+MapboxGL.m25
-rw-r--r--platform/ios/uitest/LaunchScreen.xib45
-rw-r--r--platform/ios/uitest/MGLTAppDelegate.h7
-rw-r--r--platform/ios/uitest/MGLTAppDelegate.m19
-rw-r--r--platform/ios/uitest/MGLTViewController.h9
-rw-r--r--platform/ios/uitest/MGLTViewController.m34
-rw-r--r--platform/ios/uitest/MapViewTests.m588
-rw-r--r--platform/ios/uitest/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h26
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMArg.h53
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMConstraint.h71
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMLocation.h36
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMMacroState.h45
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMRecorder.h39
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMStubRecorder.h56
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMock.h84
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMockObject.h74
-rw-r--r--platform/ios/uitest/OCMock/libOCMock.abin2071640 -> 0 bytes
m---------platform/ios/uitest/OHHTTPStubs0
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/project.pbxproj546
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout41
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout65
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme136
-rw-r--r--platform/ios/uitest/main.m9
-rwxr-xr-xplatform/ios/vendor/SMCalloutView/SMCalloutView.m38
m---------platform/ios/vendor/mapbox-events-ios0
-rw-r--r--platform/linux/README.md20
-rw-r--r--platform/linux/config.cmake27
-rw-r--r--platform/macos/CHANGELOG.md16
-rw-r--r--platform/macos/DEVELOPING.md16
-rw-r--r--platform/macos/INSTALL.md36
-rw-r--r--platform/macos/Mapbox-macOS-SDK-symbols.podspec2
-rw-r--r--platform/macos/Mapbox-macOS-SDK.podspec2
-rw-r--r--platform/macos/app/AppDelegate.m14
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.h2
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.m6
-rw-r--r--platform/macos/app/MapDocument.m12
-rw-r--r--platform/macos/config.cmake5
-rw-r--r--platform/macos/docs/doc-README.md2
-rw-r--r--platform/macos/docs/pod-README.md4
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj4
-rw-r--r--platform/macos/src/MGLMapView+IBAdditions.mm14
-rw-r--r--platform/macos/src/MGLMapView.h34
-rw-r--r--platform/macos/src/MGLMapView.mm50
-rw-r--r--platform/node/DEVELOPING.md8
-rw-r--r--platform/node/README.md3
-rw-r--r--platform/node/index.js3
-rw-r--r--platform/node/src/node_expression.cpp2
-rw-r--r--platform/node/src/node_map.cpp44
-rw-r--r--platform/node/src/node_map.hpp4
-rw-r--r--platform/node/src/node_request.cpp3
-rw-r--r--platform/node/test/ignores.json19
-rw-r--r--platform/qt/README.md11
-rw-r--r--platform/qt/app/mapwindow.cpp7
-rw-r--r--platform/qt/app/mapwindow.hpp1
-rw-r--r--platform/qt/config.qdocconf2
-rw-r--r--platform/qt/include/qmapbox.hpp10
-rw-r--r--platform/qt/include/qmapboxgl.hpp9
-rw-r--r--platform/qt/src/qmapbox.cpp14
-rw-r--r--platform/qt/src/qmapboxgl.cpp62
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.cpp29
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.hpp1
-rw-r--r--platform/qt/src/sqlite3.cpp294
-rwxr-xr-xscripts/generate-shaders.js2
-rwxr-xr-xscripts/generate-style-code.js42
-rw-r--r--scripts/style-spec.js1
-rw-r--r--src/csscolorparser/csscolorparser.cpp6
-rw-r--r--src/mbgl/geometry/feature_index.cpp10
-rw-r--r--src/mbgl/geometry/feature_index.hpp10
-rw-r--r--src/mbgl/gl/context.cpp4
-rw-r--r--src/mbgl/layout/symbol_layout.cpp6
-rw-r--r--src/mbgl/layout/symbol_layout.hpp2
-rw-r--r--src/mbgl/map/map.cpp5
-rw-r--r--src/mbgl/map/transform.cpp57
-rw-r--r--src/mbgl/map/transform.hpp2
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp4
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp2
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp3
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp1
-rw-r--r--src/mbgl/renderer/render_tile.hpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp8
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp40
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp4
-rw-r--r--src/mbgl/shaders/line.cpp3
-rw-r--r--src/mbgl/storage/resource.cpp8
-rw-r--r--src/mbgl/style/conversion/tileset.cpp17
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp9
-rw-r--r--src/mbgl/style/expression/match.cpp18
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.cpp34
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.hpp4
-rw-r--r--src/mbgl/text/placement.cpp9
-rw-r--r--src/mbgl/tile/custom_geometry_tile.cpp6
-rw-r--r--src/mbgl/tile/geometry_tile.hpp1
-rw-r--r--src/mbgl/tile/tile.hpp2
-rw-r--r--src/mbgl/util/compression.cpp2
-rw-r--r--src/mbgl/util/http_header.cpp1
-rw-r--r--src/mbgl/util/i18n.cpp37
-rw-r--r--src/mbgl/util/i18n.hpp2
-rw-r--r--src/mbgl/util/io.cpp4
-rw-r--r--src/mbgl/util/throttler.cpp36
-rw-r--r--src/mbgl/util/throttler.hpp22
-rw-r--r--src/mbgl/util/tile_cover.cpp104
-rw-r--r--src/mbgl/util/tile_cover.hpp24
-rw-r--r--src/mbgl/util/tile_cover_impl.cpp365
-rw-r--r--src/mbgl/util/tile_cover_impl.hpp90
-rw-r--r--src/mbgl/util/tiny_sdf.cpp2
-rw-r--r--src/mbgl/util/token.hpp11
-rw-r--r--src/mbgl/util/url.cpp5
-rw-r--r--test/api/custom_layer.test.cpp2
-rw-r--r--test/fixtures/offline_database/satellite_test.dbbin0 -> 114688 bytes
-rw-r--r--test/gl/bucket.test.cpp3
-rw-r--r--test/src/mbgl/test/util.cpp6
-rw-r--r--test/src/mbgl/test/util.hpp20
-rw-r--r--test/storage/offline_database.test.cpp81
-rw-r--r--test/storage/sqlite.test.cpp47
-rw-r--r--test/style/conversion/tileset.test.cpp2
-rw-r--r--test/style/expression/expression.test.cpp8
-rw-r--r--test/text/cross_tile_symbol_index.test.cpp24
-rw-r--r--test/util/tile_cover.test.cpp232
-rw-r--r--test/util/tile_range.test.cpp8
-rw-r--r--test/util/token.test.cpp3
351 files changed, 6270 insertions, 5969 deletions
diff --git a/.gitignore b/.gitignore
index 0f4fa77858..b32baaac09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,8 @@ xcuserdata
/test/fixtures/api/2.png
/test/fixtures/offline_database/offline.db
/test/fixtures/offline_database/offline.db-*
+/test/fixtures/offline_database/satellite.db
+/test/fixtures/offline_database/satellite.db-*
/test/fixtures/offline_database/invalid.db
/test/fixtures/offline_database/invalid.db-*
/test/fixtures/offline_database/migrated.db
@@ -38,4 +40,4 @@ test/fixtures/storage/assets.zip
# Generated list files from code generation
/scripts/generate-cmake-files.list
/scripts/generate-shaders.list
-/scripts/generate-style-code.list \ No newline at end of file
+/scripts/generate-style-code.list
diff --git a/.gitmodules b/.gitmodules
index e5be61a921..39221b1bd3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,13 +1,6 @@
-[submodule "platform/ios/uitest/KIF"]
- path = platform/ios/uitest/KIF
- url = https://github.com/kif-framework/KIF.git
-[submodule "platform/ios/uitest/OHHTTPStubs"]
- path = platform/ios/uitest/OHHTTPStubs
- url = https://github.com/AliSoftware/OHHTTPStubs.git
[submodule "mapbox-gl-js"]
path = mapbox-gl-js
url = https://github.com/mapbox/mapbox-gl-js.git
[submodule "platform/ios/vendor/mapbox-events-ios"]
path = platform/ios/vendor/mapbox-events-ios
url = https://github.com/mapbox/mapbox-events-ios.git
- branch = boundsj-add-namespace-header
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8307191a3f..c2f7134de7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,13 +15,9 @@ include(cmake/xcode.cmake)
if(WITH_CXX11ABI)
set(MASON_CXXABI_SUFFIX -cxx11abi)
- if(CMAKE_COMPILER_IS_GNUCXX)
- add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
- endif()
+ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
else()
- if(CMAKE_COMPILER_IS_GNUCXX)
- add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
- endif()
+ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
endif()
if(WITH_OSMESA AND WITH_EGL)
@@ -170,7 +166,7 @@ if(COMMAND mbgl_platform_offline)
include(cmake/offline.cmake)
endif()
-if(COMMAND mbgl_platform_node)
+if(WITH_NODEJS AND COMMAND mbgl_platform_node)
include(cmake/node.cmake)
endif()
diff --git a/INSTALL.md b/INSTALL.md
index a28348d15c..463d199d10 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,56 +1,15 @@
-# Building & Developing Mapbox GL Native from Source
+# Building & Developing from Source
-**Just trying to use Mapbox GL Native? You don't need to read this stuff! We
+**Just trying to use one of the Mapbox Maps SDKs? You don't need to read this stuff! We
provide [easy-to-install, prebuilt versions of the Mapbox Maps SDKs for iOS and Android
that you can download instantly and get started with fast](https://www.mapbox.com/install/).**
-Still with us? These are the instructions you'll need to build Mapbox GL Native
-from source on a variety of platforms and set up a development environment.
+If you're certain you need to build from source, rather than using a prebuilt SDK, please
+refer to the installation instructions for the platform of interest:
-Your journey will start with installing dependencies, then getting the source code, and
-then setting up a development environment, which varies depending on your
-operating system and what platform you want to develop for.
-
-## 1: Installing dependencies
-
-### macOS
-
- 1. Install [Xcode](https://developer.apple.com/xcode/)
- 2. Launch Xcode and install any updates
- 3. Install [Homebrew](http://brew.sh)
- 4. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org) with `brew install nodejs cmake ccache`
- 5. Install [xcpretty](https://github.com/supermarin/xcpretty) with `[sudo] gem install xcpretty` (optional, used for prettifying command line builds)
-
-### Linux
-
-Install the following:
-
- - `clang++` 3.5 or later or `g++` 4.9 or later
- - [git](https://git-scm.com/)
- - [CMake](https://cmake.org/) 3.1 or later
- - [cURL](https://curl.haxx.se)
- - [Node.js](https://nodejs.org/) 4.2.1 or later
- - [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL)
- - [ccache](https://ccache.samba.org) (optional, improves recompilation performance)
-
-## 2: Getting the source
-
- Clone the git repository:
-
- git clone https://github.com/mapbox/mapbox-gl-native.git
- cd mapbox-gl-native
-
-## 3: Setting up a development environment & building
-
-See the relevant SDK documentation for next steps:
-
-* [Maps SDK for Android](platform/android/)
-* [Maps SDK for iOS](platform/ios/)
-* [Maps SDK for macOS](platform/macos/)
-* [Mapbox Qt SDK](platform/qt/)
-* [Mapbox GL Native on Linux](platform/linux/)
-* [node-mapbox-gl-native](platform/node/)
-
-## 4: Keeping up to date
-
-This repository uses Git submodules, which should be automatically checked out when you first run a `make` command for one of the above platforms. These submodules are not updated automatically and we recommended that you run `git submodule update` after pulling down new commits to this repository.
+* [Mapbox Maps SDK for Android](platform/android/README.md)
+* [Mapbox Maps SDK for iOS](platform/ios/INSTALL.md)
+* [Mapbox Maps SDK for macOS](platform/macos/INSTALL.md)
+* [Mapbox Maps SDK for Qt](platform/qt/README.md)
+* [Mapbox GL Native on Linux](platform/linux/README.md)
+* [node-mapbox-gl-native](platform/node/DEVELOPING.md)
diff --git a/Makefile b/Makefile
index 5c521d674a..c2daa617b4 100644
--- a/Makefile
+++ b/Makefile
@@ -111,8 +111,7 @@ run-benchmark-%: benchmark
$(MACOS_OUTPUT_PATH)/$(BUILDTYPE)/mbgl-benchmark --benchmark_filter=$* ${BENCHMARK_ARGS}
.PHONY: node-benchmark
-node-benchmark: $(MACOS_PROJ_PATH)
- set -o pipefail && $(MACOS_XCODEBUILD) -scheme 'node-benchmark' build $(XCPRETTY)
+node-benchmark: node
.PHONY: run-node-benchmark
run-node-benchmark: node-benchmark
@@ -136,7 +135,11 @@ offline: $(MACOS_PROJ_PATH)
.PHONY: node
node: $(MACOS_PROJ_PATH)
- set -o pipefail && $(MACOS_XCODEBUILD) -scheme 'mbgl-node' build $(XCPRETTY)
+ set -o pipefail && $(MACOS_XCODEBUILD) -scheme 'mbgl-node (Active ABI)' build $(XCPRETTY)
+
+.PHONY: node-all
+node-all: $(MACOS_PROJ_PATH)
+ set -o pipefail && $(MACOS_XCODEBUILD) -scheme 'mbgl-node (All ABIs)' build $(XCPRETTY)
.PHONY: macos-test
macos-test: $(MACOS_PROJ_PATH)
@@ -362,7 +365,11 @@ run-glfw-app: glfw-app
.PHONY: node
node: $(LINUX_BUILD)
- $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(LINUX_OUTPUT_PATH) mbgl-node
+ $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(LINUX_OUTPUT_PATH) mbgl-node.active
+
+.PHONY: node-all
+node-all: $(LINUX_BUILD)
+ $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(LINUX_OUTPUT_PATH) mbgl-node.all
.PHONY: compdb
compdb: $(LINUX_BUILD)
@@ -473,12 +480,10 @@ test-node-recycle-map: node
#### Android targets ###########################################################
-MBGL_ANDROID_ABIS = arm-v5;armeabi
-MBGL_ANDROID_ABIS += arm-v7;armeabi-v7a
+MBGL_ANDROID_ABIS = arm-v7;armeabi-v7a
MBGL_ANDROID_ABIS += arm-v8;arm64-v8a
MBGL_ANDROID_ABIS += x86;x86
MBGL_ANDROID_ABIS += x86-64;x86_64
-MBGL_ANDROID_ABIS += mips;mips
MBGL_ANDROID_LOCAL_WORK_DIR = /data/local/tmp/core-tests
MBGL_ANDROID_LIBDIR = lib$(if $(filter arm-v8 x86-64,$1),64)
@@ -619,7 +624,7 @@ run-android-unit-test-%: platform/android/gradle/configuration.gradle
# Builds a release package of the Android SDK
.PHONY: apackage
apackage: platform/android/gradle/configuration.gradle
- make android-lib-arm-v5 && make android-lib-arm-v7 && make android-lib-arm-v8 && make android-lib-x86 && make android-lib-x86-64 && make android-lib-mips
+ make android-lib-arm-v7 && make android-lib-arm-v8 && make android-lib-x86 && make android-lib-x86-64
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=all assemble$(BUILDTYPE)
# Build test app instrumentation tests apk and test app apk for all abi's
@@ -687,6 +692,11 @@ endif
android-configuration: platform/android/gradle/configuration.gradle
cat platform/android/gradle/configuration.gradle
+# Creates a dependency graph using Graphviz
+.PHONY: android-graph
+android-graph:
+ cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:generateDependencyGraphMapboxLibraries
+
#### Miscellaneous targets #####################################################
.PHONY: style-code
@@ -701,6 +711,7 @@ codestyle:
.PHONY: clean
clean:
-rm -rf ./build \
+ ./lib/*.node \
./platform/android/gradle/configuration.gradle \
./platform/android/MapboxGLAndroidSDK/build \
./platform/android/MapboxGLAndroidSDK/.externalNativeBuild \
diff --git a/README.md b/README.md
index 2b24d7d567..0d6e731103 100644
--- a/README.md
+++ b/README.md
@@ -13,15 +13,15 @@ This repository hosts the cross-platform Mapbox GL Native library, plus convenie
| [Mapbox Maps SDK for iOS](platform/ios/) | Objective-C or Swift | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
| [Mapbox Maps SDK for macOS](platform/macos/) | Objective-C, Swift, or AppleScript | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
| [node-mapbox-gl-native](platform/node/) | Node.js | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
-| [Mapbox Qt SDK](platform/qt) | C++03 | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native) |
+| [Mapbox Maps SDK for Qt](platform/qt) | C++03 | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native) |
Additional Mapbox GL Native–based libraries for **hybrid applications** are developed outside of this repository:
| Toolkit | Android | iOS | Developer |
| ---------------------------------------- | --------|-----|------------ |
-| [React Native](https://github.com/mapbox/react-native-mapbox-gl/) ([npm](https://www.npmjs.com/package/react-native-mapbox-gl)) | :white_check_mark: | :white_check_mark: | Mapbox |
+| [React Native](https://github.com/mapbox/react-native-mapbox-gl/) ([npm](https://www.npmjs.com/package/@mapbox/react-native-mapbox-gl)) | :white_check_mark: | :white_check_mark: | Mapbox |
| [Apache Cordova](http://plugins.telerik.com/cordova/plugin/mapbox/) ([npm](https://www.npmjs.com/package/cordova-plugin-mapbox)) | :white_check_mark: | :white_check_mark: | Telerik |
-| [NativeScript](http://plugins.telerik.com/nativescript/plugin/mapbox/) ([npm](https://www.npmjs.com/package/nativescript-mapbox/)) | :white_check_mark: | :white_check_mark: | Telerik |
+| [NativeScript](https://market.nativescript.org/plugins/nativescript-mapbox/) ([npm](https://www.npmjs.com/package/nativescript-mapbox/)) | :white_check_mark: | :white_check_mark: | Telerik |
| [Xamarin](https://components.xamarin.com/view/mapboxsdk/) | :white_check_mark: | :white_check_mark: | Xamarin |
If your platform or hybrid application framework isn’t listed here, consider embedding [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) using the standard Web capabilities on your platform.
diff --git a/benchmark/util/tilecover.benchmark.cpp b/benchmark/util/tilecover.benchmark.cpp
new file mode 100644
index 0000000000..186de6f216
--- /dev/null
+++ b/benchmark/util/tilecover.benchmark.cpp
@@ -0,0 +1,96 @@
+#include <benchmark/benchmark.h>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/map/transform.hpp>
+
+using namespace mbgl;
+
+static const LatLngBounds sanFrancisco =
+ LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
+
+static void TileCountBounds(benchmark::State& state) {
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto count = util::tileCount(sanFrancisco, 10);
+ length += count;
+ }
+}
+
+static void TileCoverPitchedViewport(benchmark::State& state) {
+ Transform transform;
+ transform.resize({ 512, 512 });
+ // slightly offset center so that tile order is better defined
+ transform.setLatLng({ 0.1, -0.1 });
+ transform.setZoom(8);
+ transform.setAngle(5.0);
+ transform.setPitch(40.0 * M_PI / 180.0);
+
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(transform.getState(), 8);
+ length += tiles.size();
+ }
+}
+
+static void TileCoverBounds(benchmark::State& state) {
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(sanFrancisco, 8);
+ length += tiles.size();
+ }
+}
+
+static const auto geomPolygon = Polygon<double>{
+ {
+ {-122.5143814086914,37.779127216982424},
+ {-122.50811576843262,37.72721239056709},
+ {-122.50313758850099,37.70820178063929},
+ {-122.3938751220703,37.707454835665274},
+ {-122.37567901611328,37.70663997801684},
+ {-122.36297607421874,37.71343018466285},
+ {-122.354736328125,37.727280276860036},
+ {-122.36469268798828,37.73868429065797},
+ {-122.38014221191408,37.75442980295571},
+ {-122.38391876220702,37.78753873820529},
+ {-122.35919952392578,37.8065289741725},
+ {-122.35679626464844,37.820632846207864},
+ {-122.3712158203125,37.835276322922695},
+ {-122.3818588256836,37.82958198283902},
+ {-122.37190246582031,37.80788523279169},
+ {-122.38735198974608,37.791337175930686},
+ {-122.40966796874999,37.812767557570204},
+ {-122.46425628662108,37.807071480609274},
+ {-122.46803283691405,37.810326435534755},
+ {-122.47901916503906,37.81168262440736},
+ {-122.48966217041016,37.78916666399649},
+ {-122.50579833984375,37.78781006166096},
+ {-122.5143814086914,37.779127216982424}
+ }
+};
+
+static void TileCoverPolygon(benchmark::State& state) {
+ std::size_t length = 0;
+
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(geomPolygon, 8);
+ length += tiles.size();
+ }
+}
+
+static void TileCountPolygon(benchmark::State& state) {
+ std::size_t length = 0;
+
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCount(geomPolygon, 16);
+ length += tiles;
+ }
+}
+
+BENCHMARK(TileCountBounds);
+BENCHMARK(TileCountPolygon);
+BENCHMARK(TileCoverPitchedViewport);
+BENCHMARK(TileCoverBounds);
+BENCHMARK(TileCoverPolygon);
+
diff --git a/circle.yml b/circle.yml
index e7e348635f..53cc6e9c7b 100644
--- a/circle.yml
+++ b/circle.yml
@@ -4,6 +4,7 @@ workflows:
version: 2
default:
jobs:
+ - nitpick
- clang-tidy:
filters:
branches:
@@ -304,7 +305,7 @@ jobs:
# ------------------------------------------------------------------------------
android-debug-arm-v7:
docker:
- - image: mbgl/7d2403f42e:android-ndk-r16b
+ - image: mbgl/feb0443038:android-ndk-r17
resource_class: large
working_directory: /src
environment:
@@ -377,7 +378,7 @@ jobs:
# ------------------------------------------------------------------------------
android-release-all:
docker:
- - image: mbgl/7d2403f42e:android-ndk-r16b
+ - image: mbgl/feb0443038:android-ndk-r17
resource_class: large
working_directory: /src
environment:
@@ -421,7 +422,7 @@ jobs:
- deploy:
name: Publish to Maven
command: |
- if [ "${CIRCLE_BRANCH}" == "release-boba" ]; then make run-android-upload-archives ; fi
+ if [ "${CIRCLE_BRANCH}" == "master" ]; then make run-android-upload-archives ; fi
# ------------------------------------------------------------------------------
@@ -865,7 +866,7 @@ jobs:
# ------------------------------------------------------------------------------
macos-debug-qt5:
macos:
- xcode: "9.2.0"
+ xcode: "9.3.0"
environment:
BUILDTYPE: Debug
HOMEBREW_NO_AUTO_UPDATE: 1
diff --git a/cmake/NodeJS.cmake b/cmake/NodeJS.cmake
deleted file mode 100644
index 8e0ec56982..0000000000
--- a/cmake/NodeJS.cmake
+++ /dev/null
@@ -1,600 +0,0 @@
-# NOTE: We're using a patched version of the original https://github.com/cjntaylor/node-cmake
-
-# Our version is in https://github.com/mapbox/node-cmake/blob/mapbox-gl-native/NodeJS.cmake and
-# contains these patches:
-# - https://github.com/cjntaylor/node-cmake/pull/20
-# - https://github.com/cjntaylor/node-cmake/pull/22
-# - https://github.com/cjntaylor/node-cmake/pull/23
-
-# Defaults for standard Node.js builds
-set(NODEJS_DEFAULT_URL https://nodejs.org/download/release)
-set(NODEJS_DEFAULT_VERSION installed)
-set(NODEJS_VERSION_FALLBACK latest)
-set(NODEJS_DEFAULT_NAME node)
-set(NODEJS_DEFAULT_CHECKSUM SHASUMS256.txt)
-set(NODEJS_DEFAULT_CHECKTYPE SHA256)
-
-include(CMakeParseArguments)
-
-# Find a path by walking upward from a base directory until the path is
-# found. Sets the variable ${PATH} to False if the path can't
-# be determined
-function(find_path_parent NAME BASE PATH)
- set(ROOT ${BASE})
- set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE)
- set(DRIVE "^[A-Za-z]?:?/$")
- while(NOT ROOT MATCHES ${DRIVE} AND NOT EXISTS ${ROOT}/${NAME})
- get_filename_component(ROOT ${ROOT} DIRECTORY)
- set(${PATH} ${ROOT}/${NAME} PARENT_SCOPE)
- endwhile()
- if(ROOT MATCHES ${DRIVE})
- set(${PATH} False PARENT_SCOPE)
- endif()
-endfunction()
-
-# Shortcut for finding standard node module locations
-macro(find_nodejs_module NAME BASE PATH)
- find_path_parent(node_modules/${NAME} ${BASE} ${PATH})
-endmacro()
-
-# Download with a bit of nice output (without spewing progress)
-function(download_file DESCRIPTION URL FILE)
- message(STATUS "Downloading: ${URL}")
- file(DOWNLOAD
- ${URL}
- ${FILE}.tmp
- ${ARGN}
- STATUS RESULT
- )
- list(GET RESULT 0 STATUS)
- if(STATUS)
- list(GET result 1 MESSAGE)
- message(FATAL_ERROR "Unable to download ${DESCRIPTION} from ${URL}: ${MESSAGE}")
- else()
- file(RENAME ${FILE}.tmp ${FILE})
- endif()
-endfunction()
-
-# Embedded win_delay_load_hook file so that this file can be copied
-# into projects directly (recommended practice)
-function(nodejs_generate_delayload_hook OUTPUT)
- file(WRITE ${OUTPUT} "")
- file(APPEND ${OUTPUT} "/*\n")
- file(APPEND ${OUTPUT} " * When this file is linked to a DLL, it sets up a delay-load hook that\n")
- file(APPEND ${OUTPUT} " * intervenes when the DLL is trying to load 'node.exe' or 'iojs.exe'\n")
- file(APPEND ${OUTPUT} " * dynamically. Instead of trying to locate the .exe file it'll just return\n")
- file(APPEND ${OUTPUT} " * a handle to the process image.\n")
- file(APPEND ${OUTPUT} " *\n")
- file(APPEND ${OUTPUT} " * This allows compiled addons to work when node.exe or iojs.exe is renamed.\n")
- file(APPEND ${OUTPUT} " */\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "#ifdef _MSC_VER\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "#ifndef DELAYIMP_INSECURE_WRITABLE_HOOKS\n")
- file(APPEND ${OUTPUT} "#define DELAYIMP_INSECURE_WRITABLE_HOOKS\n")
- file(APPEND ${OUTPUT} "#endif\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "#ifndef WIN32_LEAN_AND_MEAN\n")
- file(APPEND ${OUTPUT} "#define WIN32_LEAN_AND_MEAN\n")
- file(APPEND ${OUTPUT} "#endif\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "#include <windows.h>\n")
- file(APPEND ${OUTPUT} "#include <Shlwapi.h>\n")
- file(APPEND ${OUTPUT} "#include <delayimp.h>\n")
- file(APPEND ${OUTPUT} "#include <string.h>\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "static FARPROC WINAPI load_exe_hook(unsigned int event, DelayLoadInfo* info) {\n")
- file(APPEND ${OUTPUT} " if (event != dliNotePreLoadLibrary) return NULL;\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " if (_stricmp(info->szDll, \"iojs.exe\") != 0 &&\n")
- file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.exe\") != 0 &&\n")
- file(APPEND ${OUTPUT} " _stricmp(info->szDll, \"node.dll\") != 0)\n")
- file(APPEND ${OUTPUT} " return NULL;\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // Get a handle to the current process executable.\n")
- file(APPEND ${OUTPUT} " HMODULE processModule = GetModuleHandle(NULL);\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // Get the path to the executable.\n")
- file(APPEND ${OUTPUT} " TCHAR processPath[_MAX_PATH];\n")
- file(APPEND ${OUTPUT} " GetModuleFileName(processModule, processPath, _MAX_PATH);\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // Get the name of the current executable.\n")
- file(APPEND ${OUTPUT} " LPSTR processName = PathFindFileName(processPath);\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // If the current process is node or iojs, then just return the proccess \n")
- file(APPEND ${OUTPUT} " // module.\n")
- file(APPEND ${OUTPUT} " if (_stricmp(processName, \"node.exe\") == 0 ||\n")
- file(APPEND ${OUTPUT} " _stricmp(processName, \"iojs.exe\") == 0) {\n")
- file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n")
- file(APPEND ${OUTPUT} " }\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // If it is another process, attempt to load 'node.dll' from the same \n")
- file(APPEND ${OUTPUT} " // directory.\n")
- file(APPEND ${OUTPUT} " PathRemoveFileSpec(processPath);\n")
- file(APPEND ${OUTPUT} " PathAppend(processPath, \"node.dll\");\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " HMODULE nodeDllModule = GetModuleHandle(processPath);\n")
- file(APPEND ${OUTPUT} " if(nodeDllModule != NULL) {\n")
- file(APPEND ${OUTPUT} " // This application has a node.dll in the same directory as the executable,\n")
- file(APPEND ${OUTPUT} " // use that.\n")
- file(APPEND ${OUTPUT} " return (FARPROC) nodeDllModule;\n")
- file(APPEND ${OUTPUT} " }\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} " // Fallback to the current executable, which must statically link to \n")
- file(APPEND ${OUTPUT} " // node.lib\n")
- file(APPEND ${OUTPUT} " return (FARPROC) processModule;\n")
- file(APPEND ${OUTPUT} "}\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "PfnDliHook __pfnDliNotifyHook2 = load_exe_hook;\n")
- file(APPEND ${OUTPUT} "\n")
- file(APPEND ${OUTPUT} "#endif\n")
-endfunction()
-
-# Sets up a project to build Node.js native modules
-# - Downloads required dependencies and unpacks them to the build directory.
-# Internet access is required the first invocation but not after (
-# provided the download is successful)
-# - Sets up several variables for building against the downloaded
-# dependencies
-# - Guarded to prevent multiple executions, so a single project hierarchy
-# will only call this once
-function(nodejs_init)
- # Prevents this function from executing more than once
- if(NODEJS_INIT)
- return()
- endif()
-
- # Regex patterns used by the init function for component extraction
- set(HEADERS_MATCH "^([A-Fa-f0-9]+)[ \t]+([^-]+)-(headers|v?[0-9.]+)-(headers|v?[0-9.]+)([.]tar[.]gz)$")
- set(LIB32_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-x86)?(/)?([^/]*)(.lib)$")
- set(LIB64_MATCH "(^[0-9A-Fa-f]+)[\t ]+(win-)?(x64/)(.*)(.lib)$")
-
- # Parse function arguments
- cmake_parse_arguments(nodejs_init
- "" "URL;NAME;VERSION;CHECKSUM;CHECKTYPE" "" ${ARGN}
- )
-
- # Allow the download URL to be overridden by command line argument
- # NODEJS_URL
- if(NODEJS_URL)
- set(URL ${NODEJS_URL})
- else()
- # Use the argument if specified, falling back to the default
- set(URL ${NODEJS_DEFAULT_URL})
- if(nodejs_init_URL)
- set(URL ${nodejs_init_URL})
- endif()
- endif()
-
- # Allow name to be overridden by command line argument NODEJS_NAME
- if(NODEJS_NAME)
- set(NAME ${NODEJS_NAME})
- else()
- # Use the argument if specified, falling back to the default
- set(NAME ${NODEJS_DEFAULT_NAME})
- if(nodejs_init_NAME)
- set(NAME ${nodejs_init_NAME})
- endif()
- endif()
-
- # Allow the checksum file to be overridden by command line argument
- # NODEJS_CHECKSUM
- if(NODEJS_CHECKSUM)
- set(CHECKSUM ${NODEJS_CHECKSUM})
- else()
- # Use the argument if specified, falling back to the default
- set(CHECKSUM ${NODEJS_DEFAULT_CHECKSUM})
- if(nodejs_init_CHECKSUM)
- set(CHECKSUM ${nodejs_init_CHECKSUM})
- endif()
- endif()
-
- # Allow the checksum type to be overriden by the command line argument
- # NODEJS_CHECKTYPE
- if(NODEJS_CHECKTYPE)
- set(CHECKTYPE ${NODEJS_CHECKTYPE})
- else()
- # Use the argument if specified, falling back to the default
- set(CHECKTYPE ${NODEJS_DEFAULT_CHECKTYPE})
- if(nodejs_init_CHECKTYPE)
- set(CHECKTYPE ${nodejs_init_CHECKTYPE})
- endif()
- endif()
-
- # Allow the version to be overridden by the command line argument
- # NODEJS_VERSION
- if(NODEJS_VERSION)
- set(VERSION ${NODEJS_VERSION})
- else()
- # Use the argument if specified, falling back to the default
- set(VERSION ${NODEJS_DEFAULT_VERSION})
- if(nodejs_init_VERSION)
- set(VERSION ${nodejs_init_VERSION})
- endif()
- endif()
-
- # "installed" is a special version that tries to use the currently
- # installed version (determined by running node)
- set(NODEJS_INSTALLED False CACHE BOOL "Node.js install status" FORCE)
- if(VERSION STREQUAL "installed")
- if(NOT NAME STREQUAL ${NODEJS_DEFAULT_NAME})
- message(FATAL_ERROR
- "'Installed' version identifier can only be used with"
- "the core Node.js library"
- )
- endif()
- # Fall back to the "latest" version if node isn't installed
- set(VERSION ${NODEJS_VERSION_FALLBACK})
- find_program(NODEJS_BINARY NAMES nodejs node)
- if(NODEJS_BINARY)
- execute_process(
- COMMAND ${NODEJS_BINARY} --version
- RESULT_VARIABLE INSTALLED_VERSION_RESULT
- OUTPUT_VARIABLE INSTALLED_VERSION
- OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- if(INSTALLED_VERSION_RESULT STREQUAL "0")
- set(NODEJS_INSTALLED True CACHE BOOL
- "Node.js install status" FORCE
- )
- set(VERSION ${INSTALLED_VERSION})
- endif()
- endif()
- endif()
-
- # Create a temporary download directory
- set(TEMP ${CMAKE_CURRENT_BINARY_DIR}/temp)
- file(MAKE_DIRECTORY ${TEMP})
-
- # Unless the target is special version "latest", the parameters
- # necessary to construct the root path are known
- if(NOT VERSION STREQUAL "latest")
- set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION})
- # Extract checksums from the existing checksum file
- set(CHECKSUM_TARGET ${ROOT}/CHECKSUM)
- endif()
-
- # If we're trying to determine the version or we haven't saved the
- # checksum file for this version, download it from the specified server
- if(VERSION STREQUAL "latest" OR
- (DEFINED ROOT AND NOT EXISTS ${ROOT}/CHECKSUM))
- if(DEFINED ROOT)
- # Clear away the old checksum in case the new one is different
- # and/or it fails to download
- file(REMOVE ${ROOT}/CHECKSUM)
- endif()
- file(REMOVE ${TEMP}/CHECKSUM)
- download_file(
- "checksum file"
- ${URL}/${VERSION}/${CHECKSUM}
- ${TEMP}/CHECKSUM
- INACTIVITY_TIMEOUT 10
- )
- # Extract checksums from the temporary file
- set(CHECKSUM_TARGET ${TEMP}/CHECKSUM)
- endif()
-
- # Extract the version, name, header archive and archive checksum
- # from the file. This first extract is what defines / specifies the
- # actual version number and name.
- file(STRINGS
- ${CHECKSUM_TARGET} HEADERS_CHECKSUM
- REGEX ${HEADERS_MATCH}
- LIMIT_COUNT 1
- )
- if(NOT HEADERS_CHECKSUM)
- file(REMOVE ${TEMP}/CHECKSUM)
- if(DEFINED ROOT)
- file(REMOVE ${ROOT}/CHECKSUM)
- endif()
- message(FATAL_ERROR "Unable to extract header archive checksum")
- endif()
- string(REGEX MATCH ${HEADERS_MATCH} HEADERS_CHECKSUM ${HEADERS_CHECKSUM})
- set(HEADERS_CHECKSUM ${CMAKE_MATCH_1})
- set(NAME ${CMAKE_MATCH_2})
- if(CMAKE_MATCH_3 STREQUAL "headers")
- set(VERSION ${CMAKE_MATCH_4})
- else()
- set(VERSION ${CMAKE_MATCH_3})
- endif()
- set(HEADERS_ARCHIVE
- ${CMAKE_MATCH_2}-${CMAKE_MATCH_3}-${CMAKE_MATCH_4}${CMAKE_MATCH_5}
- )
- # Make sure that the root directory exists, and that the checksum
- # file has been moved over from temp
- if(DEFINED ROOT)
- set(OLD_ROOT ${ROOT})
- endif()
- set(ROOT ${CMAKE_CURRENT_BINARY_DIR}/${NAME}/${VERSION})
- if(DEFINED OLD_ROOT AND NOT ROOT STREQUAL "${OLD_ROOT}")
- file(REMOVE ${TEMP}/CHECKSUM)
- file(REMOVE ${ROOT}/CHECKSUM)
- message(FATAL_ERROR "Version/Name mismatch")
- endif()
- file(MAKE_DIRECTORY ${ROOT})
- if(EXISTS ${TEMP}/CHECKSUM)
- file(REMOVE ${ROOT}/CHECKSUM)
- file(RENAME ${TEMP}/CHECKSUM ${ROOT}/CHECKSUM)
- endif()
-
- # Now that its fully resolved, report the name and version of Node.js being
- # used
- message(STATUS "NodeJS: Using ${NAME}, version ${VERSION}")
-
- # Download the headers for the version being used
- # Theoretically, these could be found by searching the installed
- # system, but in practice, this can be error prone. They're provided
- # on the download servers, so just use the ones there.
- if(NOT EXISTS ${ROOT}/include)
- file(REMOVE ${TEMP}/${HEADERS_ARCHIVE})
- download_file(
- "Node.js headers"
- ${URL}/${VERSION}/${HEADERS_ARCHIVE}
- ${TEMP}/${HEADERS_ARCHIVE}
- INACTIVITY_TIMEOUT 10
- EXPECTED_HASH ${CHECKTYPE}=${HEADERS_CHECKSUM}
- )
- execute_process(
- COMMAND ${CMAKE_COMMAND} -E tar xfz ${TEMP}/${HEADERS_ARCHIVE}
- WORKING_DIRECTORY ${TEMP}
- )
-
- # This adapts the header extraction to support a number of different
- # header archive contents in addition to the one used by the
- # default Node.js library
- unset(NODEJS_HEADERS_PATH CACHE)
- find_path(NODEJS_HEADERS_PATH
- NAMES src include
- PATHS
- ${TEMP}/${NAME}-${VERSION}-headers
- ${TEMP}/${NAME}-${VERSION}
- ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION}-headers
- ${TEMP}/${NODEJS_DEFAULT_NAME}-${VERSION}
- ${TEMP}/${NODEJS_DEFAULT_NAME}
- ${TEMP}
- NO_DEFAULT_PATH
- )
- if(NOT NODEJS_HEADERS_PATH)
- message(FATAL_ERROR "Unable to find extracted headers folder")
- endif()
-
- # Move the headers into a standard location with a standard layout
- file(REMOVE ${TEMP}/${HEADERS_ARCHIVE})
- file(REMOVE_RECURSE ${ROOT}/include)
- if(EXISTS ${NODEJS_HEADERS_PATH}/include/node)
- file(RENAME ${NODEJS_HEADERS_PATH}/include/node ${ROOT}/include)
- elseif(EXISTS ${NODEJS_HEADERS_PATH}/src)
- file(MAKE_DIRECTORY ${ROOT}/include)
- if(NOT EXISTS ${NODEJS_HEADERS_PATH}/src)
- file(REMOVE_RECURSE ${ROOT}/include)
- message(FATAL_ERROR "Unable to find core headers")
- endif()
- file(COPY ${NODEJS_HEADERS_PATH}/src/
- DESTINATION ${ROOT}/include
- )
- if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/uv/include)
- file(REMOVE_RECURSE ${ROOT}/include)
- message(FATAL_ERROR "Unable to find libuv headers")
- endif()
- file(COPY ${NODEJS_HEADERS_PATH}/deps/uv/include/
- DESTINATION ${ROOT}/include
- )
- if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/v8/include)
- file(REMOVE_RECURSE ${ROOT}/include)
- message(FATAL_ERROR "Unable to find v8 headers")
- endif()
- file(COPY ${NODEJS_HEADERS_PATH}/deps/v8/include/
- DESTINATION ${ROOT}/include
- )
- if(NOT EXISTS ${NODEJS_HEADERS_PATH}/deps/zlib)
- file(REMOVE_RECURSE ${ROOT}/include)
- message(FATAL_ERROR "Unable to find zlib headers")
- endif()
- file(COPY ${NODEJS_HEADERS_PATH}/deps/zlib/
- DESTINATION ${ROOT}/include
- )
- endif()
- file(REMOVE_RECURSE ${NODEJS_HEADERS_PATH})
- unset(NODEJS_HEADERS_PATH CACHE)
- endif()
-
- # Only download the libraries on windows, since its the only place
- # its necessary. Note, this requires rerunning CMake if moving
- # a module from one platform to another (should happen automatically
- # with most generators)
- if(WIN32)
- # Download the win32 library for linking
- file(STRINGS
- ${ROOT}/CHECKSUM LIB32_CHECKSUM
- LIMIT_COUNT 1
- REGEX ${LIB32_MATCH}
- )
- if(NOT LIB32_CHECKSUM)
- message(FATAL_ERROR "Unable to extract x86 library checksum")
- endif()
- string(REGEX MATCH ${LIB32_MATCH} LIB32_CHECKSUM ${LIB32_CHECKSUM})
- set(LIB32_CHECKSUM ${CMAKE_MATCH_1})
- set(LIB32_PATH win-x86)
- set(LIB32_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5})
- set(LIB32_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB32_NAME})
- if(NOT EXISTS ${ROOT}/${LIB32_PATH})
- file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH})
- download_file(
- "Node.js windows library (32-bit)"
- ${URL}/${VERSION}/${LIB32_TARGET}
- ${TEMP}/${LIB32_PATH}/${LIB32_NAME}
- INACTIVITY_TIMEOUT 10
- EXPECTED_HASH ${CHECKTYPE}=${LIB32_CHECKSUM}
- )
- file(REMOVE_RECURSE ${ROOT}/${LIB32_PATH})
- file(MAKE_DIRECTORY ${ROOT}/${LIB32_PATH})
- file(RENAME
- ${TEMP}/${LIB32_PATH}/${LIB32_NAME}
- ${ROOT}/${LIB32_PATH}/${LIB32_NAME}
- )
- file(REMOVE_RECURSE ${TEMP}/${LIB32_PATH})
- endif()
-
- # Download the win64 library for linking
- file(STRINGS
- ${ROOT}/CHECKSUM LIB64_CHECKSUM
- LIMIT_COUNT 1
- REGEX ${LIB64_MATCH}
- )
- if(NOT LIB64_CHECKSUM)
- message(FATAL_ERROR "Unable to extract x64 library checksum")
- endif()
- string(REGEX MATCH ${LIB64_MATCH} LIB64_CHECKSUM ${LIB64_CHECKSUM})
- set(LIB64_CHECKSUM ${CMAKE_MATCH_1})
- set(LIB64_PATH win-x64)
- set(LIB64_NAME ${CMAKE_MATCH_4}${CMAKE_MATCH_5})
- set(LIB64_TARGET ${CMAKE_MATCH_2}${CMAKE_MATCH_3}${LIB64_NAME})
- if(NOT EXISTS ${ROOT}/${LIB64_PATH})
- file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH})
- download_file(
- "Node.js windows library (64-bit)"
- ${URL}/${VERSION}/${LIB64_TARGET}
- ${TEMP}/${LIB64_PATH}/${LIB64_NAME}
- INACTIVITY_TIMEOUT 10
- EXPECTED_HASH ${CHECKTYPE}=${LIB64_CHECKSUM}
- )
- file(REMOVE_RECURSE ${ROOT}/${LIB64_PATH})
- file(MAKE_DIRECTORY ${ROOT}/${LIB64_PATH})
- file(RENAME
- ${TEMP}/${LIB64_PATH}/${LIB64_NAME}
- ${ROOT}/${LIB64_PATH}/${LIB64_NAME}
- )
- file(REMOVE_RECURSE ${TEMP}/${LIB64_PATH})
- endif()
- endif()
-
- # The downloaded headers should always be set for inclusion
- list(APPEND INCLUDE_DIRS ${ROOT}/include)
-
- # Look for the NAN module, and add it to the includes
- find_nodejs_module(
- nan
- ${CMAKE_CURRENT_SOURCE_DIR}
- NODEJS_NAN_DIR
- )
- if(NODEJS_NAN_DIR)
- list(APPEND INCLUDE_DIRS ${NODEJS_NAN_DIR})
- endif()
-
- # Under windows, we need a bunch of libraries (due to the way
- # dynamic linking works)
- if(WIN32)
- # Generate and use a delay load hook to allow the node binary
- # name to be changed while still loading native modules
- set(DELAY_LOAD_HOOK ${CMAKE_CURRENT_BINARY_DIR}/win_delay_load_hook.c)
- nodejs_generate_delayload_hook(${DELAY_LOAD_HOOK})
- set(SOURCES ${DELAY_LOAD_HOOK})
-
- # Necessary flags to get delayload working correctly
- list(APPEND LINK_FLAGS
- "-IGNORE:4199"
- "-DELAYLOAD:iojs.exe"
- "-DELAYLOAD:node.exe"
- "-DELAYLOAD:node.dll"
- )
-
- # Core system libraries used by node
- list(APPEND LIBRARIES
- kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
- advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
- odbc32.lib Shlwapi.lib DelayImp.lib
- )
-
- # Also link to the node stub itself (downloaded above)
- if(CMAKE_CL_64)
- list(APPEND LIBRARIES ${ROOT}/${LIB64_PATH}/${LIB64_NAME})
- else()
- list(APPEND LIBRARIES ${ROOT}/${LIB32_PATH}/${LIB32_NAME})
- endif()
- else()
- # Non-windows platforms should use these flags
- list(APPEND DEFINITIONS _LARGEFILE_SOURCE _FILE_OFFSET_BITS=64)
- endif()
-
- # Special handling for OSX / clang to allow undefined symbols
- # Define is required by node on OSX
- if(APPLE)
- list(APPEND LINK_FLAGS "-undefined dynamic_lookup")
- list(APPEND DEFINITIONS _DARWIN_USE_64_BIT_INODE=1)
- endif()
-
- # Export all settings for use as arguments in the rest of the build
- set(NODEJS_VERSION ${VERSION} PARENT_SCOPE)
- set(NODEJS_SOURCES ${SOURCES} PARENT_SCOPE)
- set(NODEJS_INCLUDE_DIRS ${INCLUDE_DIRS} PARENT_SCOPE)
- set(NODEJS_LIBRARIES ${LIBRARIES} PARENT_SCOPE)
- set(NODEJS_LINK_FLAGS ${LINK_FLAGS} PARENT_SCOPE)
- set(NODEJS_DEFINITIONS ${DEFINITIONS} PARENT_SCOPE)
-
- # Prevents this function from executing more than once
- set(NODEJS_INIT TRUE PARENT_SCOPE)
-endfunction()
-
-# Helper function for defining a node module
-# After nodejs_init, all of the settings and dependencies necessary to do
-# this yourself are defined, but this helps make sure everything is configured
-# correctly. Feel free to use it as a model to do this by hand (or to
-# tweak this configuration if you need something custom).
-function(add_nodejs_module NAME)
- # Make sure node is initialized (variables set) before defining the module
- if(NOT NODEJS_INIT)
- message(FATAL_ERROR
- "Node.js has not been initialized. "
- "Call nodejs_init before adding any modules"
- )
- endif()
- # In order to match node-gyp, we need to build into type specific folders
- # ncmake takes care of this, but be sure to set CMAKE_BUILD_TYPE yourself
- # if invoking CMake directly
- if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
- message(FATAL_ERROR
- "Configuration type must be specified. "
- "Set CMAKE_BUILD_TYPE or use a different generator"
- )
- endif()
-
- # A node module is a shared library
- add_library(${NAME} SHARED ${NODEJS_SOURCES} ${ARGN})
- # Add compiler defines for the module
- # Two helpful ones:
- # MODULE_NAME must match the name of the build library, define that here
- target_compile_definitions(${NAME}
- PRIVATE MODULE_NAME=${NAME}
- PUBLIC ${NODEJS_DEFINITIONS}
- )
- # This properly defines includes for the module
- target_include_directories(${NAME} PUBLIC ${NODEJS_INCLUDE_DIRS})
-
- # Add link flags to the module
- target_link_libraries(${NAME} ${NODEJS_LIBRARIES})
-
- # Set required properties for the module to build properly
- # Correct naming, symbol visiblity and C++ standard
- set_target_properties(${NAME} PROPERTIES
- OUTPUT_NAME ${NAME}
- PREFIX ""
- SUFFIX ".node"
- MACOSX_RPATH ON
- C_VISIBILITY_PRESET hidden
- CXX_VISIBILITY_PRESET hidden
- POSITION_INDEPENDENT_CODE TRUE
- CMAKE_CXX_STANDARD_REQUIRED TRUE
- CXX_STANDARD 11
- LINK_FLAGS "${NODEJS_LINK_FLAGS}"
- )
-
- # Make sure we're buiilding in a build specific output directory
- # Only necessary on single-target generators (Make, Ninja)
- # Multi-target generators do this automatically
- # This (luckily) mirrors node-gyp conventions
- if(NOT CMAKE_CONFIGURATION_TYPES)
- set_property(TARGET ${NAME} PROPERTY
- LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE}
- )
- endif()
-endfunction()
diff --git a/cmake/benchmark-files.cmake b/cmake/benchmark-files.cmake
index fdafcf30f9..21547eb9c4 100644
--- a/cmake/benchmark-files.cmake
+++ b/cmake/benchmark-files.cmake
@@ -23,5 +23,6 @@ set(MBGL_BENCHMARK_FILES
# util
benchmark/util/dtoa.benchmark.cpp
+ benchmark/util/tilecover.benchmark.cpp
)
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 208c598872..7e48b336b4 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -746,11 +746,11 @@ set(MBGL_CORE_FILES
src/mbgl/util/stopwatch.hpp
src/mbgl/util/string.cpp
src/mbgl/util/thread_local.hpp
- src/mbgl/util/throttler.cpp
- src/mbgl/util/throttler.hpp
src/mbgl/util/tile_coordinate.hpp
src/mbgl/util/tile_cover.cpp
src/mbgl/util/tile_cover.hpp
+ src/mbgl/util/tile_cover_impl.cpp
+ src/mbgl/util/tile_cover_impl.hpp
src/mbgl/util/tile_range.hpp
src/mbgl/util/tiny_sdf.cpp
src/mbgl/util/tiny_sdf.hpp
diff --git a/cmake/loop-uv.cmake b/cmake/loop-uv.cmake
index f4e7ced00e..e1d3166b63 100644
--- a/cmake/loop-uv.cmake
+++ b/cmake/loop-uv.cmake
@@ -1,18 +1,14 @@
-add_library(mbgl-loop-uv STATIC
- platform/default/async_task.cpp
- platform/default/run_loop.cpp
- platform/default/timer.cpp
-)
+add_library(mbgl-loop-uv INTERFACE)
-target_include_directories(mbgl-loop-uv
- PRIVATE include
- PRIVATE src
+target_sources(mbgl-loop-uv INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/async_task.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/run_loop.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/timer.cpp
)
-target_link_libraries(mbgl-loop-uv
- PRIVATE mbgl-core
+target_include_directories(mbgl-loop-uv INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
)
create_source_groups(mbgl-loop-uv)
-
-xcode_create_scheme(TARGET mbgl-loop-uv) \ No newline at end of file
diff --git a/cmake/mason.cmake b/cmake/mason.cmake
index bc31feeb5f..6116067080 100644
--- a/cmake/mason.cmake
+++ b/cmake/mason.cmake
@@ -23,9 +23,7 @@ function(mason_detect_platform)
if(NOT MASON_PLATFORM_VERSION)
# Android Studio only passes ANDROID_ABI, but we need to adjust that to the Mason
if(MASON_PLATFORM STREQUAL "android" AND NOT MASON_PLATFORM_VERSION)
- if (ANDROID_ABI STREQUAL "armeabi")
- set(MASON_PLATFORM_VERSION "arm-v5-9" PARENT_SCOPE)
- elseif (ANDROID_ABI STREQUAL "armeabi-v7a")
+ if (ANDROID_ABI STREQUAL "armeabi-v7a")
set(MASON_PLATFORM_VERSION "arm-v7-9" PARENT_SCOPE)
elseif (ANDROID_ABI STREQUAL "arm64-v8a")
set(MASON_PLATFORM_VERSION "arm-v8-21" PARENT_SCOPE)
@@ -33,10 +31,6 @@ function(mason_detect_platform)
set(MASON_PLATFORM_VERSION "x86-9" PARENT_SCOPE)
elseif (ANDROID_ABI STREQUAL "x86_64")
set(MASON_PLATFORM_VERSION "x86-64-21" PARENT_SCOPE)
- elseif (ANDROID_ABI STREQUAL "mips")
- set(MASON_PLATFORM_VERSION "mips-9" PARENT_SCOPE)
- elseif (ANDROID_ABI STREQUAL "mips64")
- set(MASON_PLATFORM_VERSION "mips-64-9" PARENT_SCOPE)
else()
message(FATAL_ERROR "Unknown ANDROID_ABI '${ANDROID_ABI}'.")
endif()
diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake
index f087c32511..c833fc4a20 100644
--- a/cmake/mbgl.cmake
+++ b/cmake/mbgl.cmake
@@ -17,12 +17,32 @@ if(WITH_NODEJS)
message(FATAL_ERROR "Could not find npm")
endif()
+ execute_process(
+ COMMAND "${NodeJS_EXECUTABLE}" -e "process.stdout.write(process.versions.node)"
+ RESULT_VARIABLE _STATUS_CODE
+ OUTPUT_VARIABLE NodeJS_VERSION
+ ERROR_VARIABLE _STATUS_MESSAGE
+ )
+ if(NOT _STATUS_CODE EQUAL 0)
+ message(FATAL_ERROR "Could not detect Node.js version: ${_STATUS_MESSAGE}")
+ endif()
+
+ execute_process(
+ COMMAND "${NodeJS_EXECUTABLE}" -e "process.stdout.write(process.versions.modules)"
+ RESULT_VARIABLE _STATUS_CODE
+ OUTPUT_VARIABLE NodeJS_ABI
+ ERROR_VARIABLE _STATUS_MESSAGE
+ )
+ if(NOT _STATUS_CODE EQUAL 0)
+ message(FATAL_ERROR "Could not detect Node.js ABI version: ${_STATUS_MESSAGE}")
+ endif()
+
function(_npm_install DIRECTORY NAME ADDITIONAL_DEPS)
SET(NPM_INSTALL_FAILED FALSE)
if("${DIRECTORY}/package.json" IS_NEWER_THAN "${DIRECTORY}/node_modules/.${NAME}.stamp")
message(STATUS "Running 'npm install' for ${NAME}...")
execute_process(
- COMMAND ${NodeJS_EXECUTABLE} ${npm_EXECUTABLE} install --ignore-scripts
+ COMMAND "${NodeJS_EXECUTABLE}" "${npm_EXECUTABLE}" install --ignore-scripts
WORKING_DIRECTORY "${DIRECTORY}"
RESULT_VARIABLE NPM_INSTALL_FAILED)
if(NOT NPM_INSTALL_FAILED)
@@ -32,7 +52,7 @@ if(WITH_NODEJS)
add_custom_command(
OUTPUT "${DIRECTORY}/node_modules/.${NAME}.stamp"
- COMMAND ${NodeJS_EXECUTABLE} ${npm_EXECUTABLE} install --ignore-scripts
+ COMMAND "${NodeJS_EXECUTABLE}" "${npm_EXECUTABLE}" install --ignore-scripts
COMMAND ${CMAKE_COMMAND} -E touch "${DIRECTORY}/node_modules/.${NAME}.stamp"
WORKING_DIRECTORY "${DIRECTORY}"
DEPENDS ${ADDITIONAL_DEPS} "${DIRECTORY}/package.json"
@@ -72,7 +92,12 @@ endif()
# Generate source groups so the files are properly sorted in IDEs like Xcode.
function(create_source_groups target)
- get_target_property(sources ${target} SOURCES)
+ get_target_property(type ${target} TYPE)
+ if(type AND type STREQUAL "INTERFACE_LIBRARY")
+ get_target_property(sources ${target} INTERFACE_SOURCES)
+ else()
+ get_target_property(sources ${target} SOURCES)
+ endif()
foreach(file ${sources})
get_filename_component(file "${file}" ABSOLUTE)
string(REGEX REPLACE "^${CMAKE_SOURCE_DIR}/" "" group "${file}")
@@ -110,7 +135,7 @@ endfunction()
if(MBGL_PLATFORM STREQUAL "ios")
execute_process(
- COMMAND git submodule update --init platform/ios/vendor/mapbox-events-ios platform/ios/uitest/KIF platform/ios/uitest/OHHTTPStubs
+ COMMAND git submodule update --init platform/ios/vendor/mapbox-events-ios
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
endif()
diff --git a/cmake/node.cmake b/cmake/node.cmake
index 0c2f556b7d..b6f7bb9dc0 100644
--- a/cmake/node.cmake
+++ b/cmake/node.cmake
@@ -1,75 +1,96 @@
# Load Node.js
-include(cmake/NodeJS.cmake)
-nodejs_init()
+include(node_modules/@mapbox/cmake-node-module/module.cmake)
-add_nodejs_module(mbgl-node
- platform/node/src/node_mapbox_gl_native.cpp
-)
+add_library(mbgl-loop-node INTERFACE)
-# NodeJS.cmake forces C++11.
-# https://github.com/cjntaylor/node-cmake/issues/18
-set_target_properties("mbgl-node" PROPERTIES CXX_STANDARD 14)
-
-target_sources(mbgl-node
- PRIVATE platform/node/src/node_logging.hpp
- PRIVATE platform/node/src/node_logging.cpp
- PRIVATE platform/node/src/node_conversion.hpp
- PRIVATE platform/node/src/node_map.hpp
- PRIVATE platform/node/src/node_map.cpp
- PRIVATE platform/node/src/node_request.hpp
- PRIVATE platform/node/src/node_request.cpp
- PRIVATE platform/node/src/node_feature.hpp
- PRIVATE platform/node/src/node_feature.cpp
- PRIVATE platform/node/src/node_thread_pool.hpp
- PRIVATE platform/node/src/node_thread_pool.cpp
- PRIVATE platform/node/src/node_expression.hpp
- PRIVATE platform/node/src/node_expression.cpp
- PRIVATE platform/node/src/util/async_queue.hpp
+target_sources(mbgl-loop-node INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/async_task.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/run_loop.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default/timer.cpp
)
-target_include_directories(mbgl-node
- PRIVATE platform/default
+target_include_directories(mbgl-loop-node INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
)
-# Use node-provided uv.h. This is not part of loop-uv.cmake because loop-uv.cmake is also
-# used by linux/config.cmake, where we need to use headers provided by mason's libuv.
-target_include_directories(mbgl-loop-uv PUBLIC ${NODEJS_INCLUDE_DIRS})
+create_source_groups(mbgl-loop-node)
+
-target_link_libraries(mbgl-node
- PRIVATE mbgl-core
- PRIVATE mbgl-loop-uv
+add_node_module(mbgl-node
+ INSTALL_DIR "lib"
+ NAN_VERSION "2.10.0"
+ EXCLUDE_NODE_ABIS 47 51 59 # Don't build old beta ABIs 5.x, 7.x, and 9.x
)
-target_add_mason_package(mbgl-node PRIVATE geojson)
+target_sources(mbgl-node INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_mapbox_gl_native.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_mapbox_gl_native.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_logging.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_logging.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_conversion.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_map.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_map.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_request.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_request.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_feature.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_feature.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_thread_pool.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_thread_pool.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_expression.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/node_expression.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/node/src/util/async_queue.hpp
+)
+
+target_include_directories(mbgl-node INTERFACE
+ ${CMAKE_CURRENT_SOURCE_DIR}/platform/default
+)
-add_custom_command(
- TARGET mbgl-node
- POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mbgl-node> ${CMAKE_SOURCE_DIR}/lib/mapbox_gl_native.node
+target_link_libraries(mbgl-node INTERFACE
+ mbgl-core
+ mbgl-loop-node
)
+target_add_mason_package(mbgl-node INTERFACE geojson)
+
+add_custom_target(mbgl-node.active DEPENDS mbgl-node.abi-${NodeJS_ABI})
+
mbgl_platform_node()
create_source_groups(mbgl-node)
-initialize_xcode_cxx_build_settings(mbgl-node)
+foreach(ABI IN LISTS mbgl-node::abis)
+ initialize_xcode_cxx_build_settings(mbgl-node.abi-${ABI})
+ xcode_create_scheme(
+ TARGET mbgl-node.abi-${ABI}
+ NAME "mbgl-node (ABI ${ABI})"
+ )
+endforeach()
+
+xcode_create_scheme(
+ TARGET mbgl-node.active
+ TYPE library
+ NAME "mbgl-node (Active ABI)"
+)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.all
+ TYPE library
+ NAME "mbgl-node (All ABIs)"
)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.active
TYPE node
- NAME "node tests"
+ NAME "node tests (Active ABI)"
ARGS
"node_modules/.bin/tape platform/node/test/js/**/*.test.js"
)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.active
TYPE node
- NAME "node render tests"
+ NAME "node render tests (Active ABI)"
ARGS
"platform/node/test/render.test.js"
OPTIONAL_ARGS
@@ -78,9 +99,9 @@ xcode_create_scheme(
)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.active
TYPE node
- NAME "node query tests"
+ NAME "node query tests (Active ABI)"
ARGS
"platform/node/test/query.test.js"
OPTIONAL_ARGS
@@ -89,9 +110,9 @@ xcode_create_scheme(
)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.active
TYPE node
- NAME "node expression tests"
+ NAME "node expression tests (Active ABI)"
ARGS
"platform/node/test/expression.test.js"
OPTIONAL_ARGS
@@ -100,9 +121,9 @@ xcode_create_scheme(
)
xcode_create_scheme(
- TARGET mbgl-node
+ TARGET mbgl-node.active
TYPE node
- NAME "node-benchmark"
+ NAME "node-benchmark (Active ABI)"
ARGS
"platform/node/test/benchmark.js"
OPTIONAL_ARGS
diff --git a/cmake/test.cmake b/cmake/test.cmake
index 183263c5a9..d6a2565979 100644
--- a/cmake/test.cmake
+++ b/cmake/test.cmake
@@ -8,6 +8,11 @@ else()
)
endif()
+
+if(NOT WITH_NODEJS)
+ target_compile_definitions(mbgl-test PRIVATE "-DTEST_HAS_SERVER=0")
+endif()
+
set_source_files_properties(test/src/mbgl/test/util.cpp PROPERTIES COMPILE_FLAGS -DNODE_EXECUTABLE="${NodeJS_EXECUTABLE}")
target_include_directories(mbgl-test
diff --git a/include/mbgl/tile/tile_id.hpp b/include/mbgl/tile/tile_id.hpp
index 11fb5ce537..dd2fba573d 100644
--- a/include/mbgl/tile/tile_id.hpp
+++ b/include/mbgl/tile/tile_id.hpp
@@ -58,10 +58,11 @@ public:
uint32_t overscaleFactor() const;
OverscaledTileID scaledTo(uint8_t z) const;
UnwrappedTileID toUnwrapped() const;
+ OverscaledTileID unwrapTo(int16_t wrap);
- const uint8_t overscaledZ;
- const int16_t wrap;
- const CanonicalTileID canonical;
+ uint8_t overscaledZ;
+ int16_t wrap;
+ CanonicalTileID canonical;
};
::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs);
@@ -84,9 +85,10 @@ public:
std::array<UnwrappedTileID, 4> children() const;
OverscaledTileID overscaleTo(uint8_t z) const;
float pixelsToTileUnits(float pixelValue, float zoom) const;
+ UnwrappedTileID unwrapTo(int16_t wrap);
- const int16_t wrap;
- const CanonicalTileID canonical;
+ int16_t wrap;
+ CanonicalTileID canonical;
};
::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs);
@@ -191,6 +193,10 @@ inline UnwrappedTileID OverscaledTileID::toUnwrapped() const {
return { wrap, canonical };
}
+inline OverscaledTileID OverscaledTileID::unwrapTo(int16_t newWrap) {
+ return { overscaledZ, newWrap, canonical };
+}
+
inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_)
: wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)),
canonical(
@@ -215,6 +221,10 @@ inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const {
return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical);
}
+inline UnwrappedTileID UnwrappedTileID::unwrapTo(int16_t newWrap) {
+ return { newWrap, canonical };
+}
+
inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const {
return wrap == parent.wrap && canonical.isChildOf(parent.canonical);
}
diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp
index b4a34521a4..65a84d8dc2 100644
--- a/include/mbgl/util/projection.hpp
+++ b/include/mbgl/util/projection.hpp
@@ -78,8 +78,9 @@ public:
return project_(latLng, worldSize(scale));
}
- static Point<double> project(const LatLng& latLng, uint8_t zoom) {
- return project_(latLng, std::pow(2.0, zoom));
+ //Returns point on tile
+ static Point<double> project(const LatLng& latLng, int32_t zoom) {
+ return project_(latLng, 1 << zoom);
}
static LatLng unproject(const Point<double>& p, double scale, LatLng::WrapMode wrapMode = LatLng::Unwrapped) {
@@ -90,16 +91,7 @@ public:
wrapMode
};
}
-
- // Project lat, lon to point in a zoom-dependent world size
- static Point<double> project(const LatLng& point, uint8_t zoom, uint16_t tileSize) {
- const double t2z = tileSize * std::pow(2, zoom);
- Point<double> pt = project_(point, t2z);
- // Flip y coordinate
- auto x = ::round(std::min(pt.x, t2z));
- auto y = ::round(std::min(t2z - pt.y, t2z));
- return { x, y };
- }
+
private:
static Point<double> project_(const LatLng& latLng, double worldSize) {
return Point<double> {
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject 021c58288cb0d5ec3af157767affda3a0492208
+Subproject a5a8dfe5b90737dbb295eaca7f41c667ae4060a
diff --git a/misc/ca-bundle.crt b/misc/ca-bundle.crt
index 29691b9733..2ec7884afd 100644
--- a/misc/ca-bundle.crt
+++ b/misc/ca-bundle.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Jan 17 00:48:54 2018 GMT
+## Certificate data from Mozilla as of: Mon Apr 16 12:40:48 2018 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.27.
-## SHA256: a3ac15b98179dd2f3c5de076d10b1d53048754372f7207c2f327510cdd78fbd8
+## SHA256: 704f02707ec6b4c4a7597a8c6039b020def11e64f3ef0605a9c3543d48038a57
##
@@ -446,60 +446,6 @@ EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
llpwrN9M
-----END CERTIFICATE-----
-Camerfirma Chambers of Commerce Root
-====================================
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
-QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
-ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
-NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
-cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
-MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
-AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
-xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
-NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
-DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
-d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
-EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
-cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
-AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
-bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
-VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
-aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
-fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
-L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
-UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
-ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
-erfutGWaIZDgqtCYvDi1czyL+Nw=
------END CERTIFICATE-----
-
-Camerfirma Global Chambersign Root
-==================================
------BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
-QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
-ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
-NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
-YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
-MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
-ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
-1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
-by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
-6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
-8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
-BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
-aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
-Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
-aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
-ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
-bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
-PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
-gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
-PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
-IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
-t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
------END CERTIFICATE-----
-
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
@@ -710,30 +656,6 @@ RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
-DST ACES CA X6
-==============
------BEGIN CERTIFICATE-----
-MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
-EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
-MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
-MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
-CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
-DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
-pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
-GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
-MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
-Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
-dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
-CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
-5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
-Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
-nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
-vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
-oKfN5XozNmr6mis=
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -976,27 +898,6 @@ FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
-Security Communication EV RootCA1
-=================================
------BEGIN CERTIFICATE-----
-MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
-U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
-dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
-BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
-Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
-/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
-WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
-ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
-bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
-9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
-SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
-iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
-Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
-mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
-T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
------END CERTIFICATE-----
-
OISTE WISeKey Global Root GA CA
===============================
-----BEGIN CERTIFICATE-----
@@ -2027,36 +1928,6 @@ NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
w9y4AyHqnxbxLFS1
-----END CERTIFICATE-----
-CA Disig Root R1
-================
------BEGIN CERTIFICATE-----
-MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
-EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
-ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
-EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
-c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
-3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
-u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
-m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
-CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
-YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
-vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
-LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
-ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
-XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
-HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
-04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
-xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
-LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
-CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
-VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
-YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
-ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
-lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
-UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
-a7+h89n07eLw4+1knj0vllJPgFOL
------END CERTIFICATE-----
-
CA Disig Root R2
================
-----BEGIN CERTIFICATE-----
diff --git a/package.json b/package.json
index 208d4e4c4a..b2102354bd 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
},
"license": "BSD-2-Clause",
"dependencies": {
- "nan": "~2.8",
+ "@mapbox/cmake-node-module": "^1.0.0",
"node-pre-gyp": "^0.6.37",
"npm-run-all": "^4.0.2"
},
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index ba14f3d93c..da813f3058 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -2,6 +2,24 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
+## 6.2.0-alpha.2 - May 25, 2018
+ - UI Thread checking [#12000](https://github.com/mapbox/mapbox-gl-native/pull/12000)
+ - Don't force having an Mapbox access token [#12001](https://github.com/mapbox/mapbox-gl-native/pull/12001)
+ - Unknown tokens in URLs are now preserved, rather than replaced with an empty string [#11787](https://github.com/mapbox/mapbox-gl-native/issues/11787)
+ - Update onMapChange Listener javadoc [#11972](https://github.com/mapbox/mapbox-gl-native/pull/11972)
+ - Set Tile loaded/rendered instead of marking tile as optional [#11985](https://github.com/mapbox/mapbox-gl-native/pull/11985)
+ - Wrap glGetString in `MBGL_CHECK_ERROR` too [#11106](https://github.com/mapbox/mapbox-gl-native/pull/11106)
+ - Accept constant expression in non-dds properties [#11960](https://github.com/mapbox/mapbox-gl-native/pull/11960)
+ - Style JSON configuration in Snapshotter [#11976](https://github.com/mapbox/mapbox-gl-native/pull/11976)
+ - Remove mips and armeabi as supported ABI, update to NDK 17 [#11458](https://github.com/mapbox/mapbox-gl-native/pull/11458)
+ - Re-assign ids when lng jumps to avoid flicker [#11938](https://github.com/mapbox/mapbox-gl-native/pull/11938)
+ - Change modifier MapView#initialize to allow subclassing [#11969](https://github.com/mapbox/mapbox-gl-native/pull/11969)
+ - Avoid symbol flickering when longitude is wrapped [#11938](https://github.com/mapbox/mapbox-gl-native/pull/11938)
+ - Fix hang when parsing very large angles for hue in hsl colors [#11968](https://github.com/mapbox/mapbox-gl-native/pull/11968)
+ - Clamp TileJSON.bounds latitudes to [-90, 90] [#11964](https://github.com/mapbox/mapbox-gl-native/pull/11964)
+ - Align URL token replacement with GL-JS [#11953](https://github.com/mapbox/mapbox-gl-native/pull/11953)
+ - Align match behaviour [#11935](https://github.com/mapbox/mapbox-gl-native/pull/11935)
+
## 6.1.3 - May 23, 2018
- Circle querying fixes [#11571](https://github.com/mapbox/mapbox-gl-native/pull/11571)
- Global symbol query [#11742](https://github.com/mapbox/mapbox-gl-native/pull/11742)
@@ -33,7 +51,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
- Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811)
- Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792)
- Add Danish localization; update Hungarian, Russian, Swedish translations [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11136)
-
+
+## 5.5.3 - May 4, 2018
+ - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800)
+
## 6.0.1 - April 17, 2018
- Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710)
diff --git a/platform/android/MapboxGLAndroidSDK/.gitignore b/platform/android/MapboxGLAndroidSDK/.gitignore
new file mode 100644
index 0000000000..c24bd2563a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/.gitignore
@@ -0,0 +1 @@
+dependency-graph-mapbox-libraries.png
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index f82968051d..21ed25e2c2 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -1,9 +1,13 @@
apply plugin: 'com.android.library'
dependencies {
- api dependenciesList.mapboxAndroidTelemetry
+ api (dependenciesList.mapboxAndroidTelemetry) {
+ exclude group: 'com.android.support', module: 'appcompat-v7'
+ }
api dependenciesList.mapboxJavaGeoJSON
- api dependenciesList.mapboxAndroidGestures
+ api (dependenciesList.mapboxAndroidGestures) {
+ exclude group: 'com.android.support', module: 'appcompat-v7'
+ }
implementation dependenciesList.supportAnnotations
implementation dependenciesList.supportFragmentV4
implementation dependenciesList.timber
@@ -87,7 +91,7 @@ android {
if (abi != 'all') {
abiFilters abi.split(' ')
} else {
- abiFilters "armeabi", "armeabi-v7a", "mips", "x86", "arm64-v8a", "x86_64"
+ abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
}
@@ -111,7 +115,7 @@ android {
}
lintOptions {
- disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission'
+ disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission', 'WrongThreadInterprocedural'
checkAllWarnings true
warningsAsErrors false
}
@@ -145,3 +149,4 @@ apply from: "${rootDir}/gradle/gradle-javadoc.gradle"
apply from: "${rootDir}/gradle/gradle-publish.gradle"
apply from: "${rootDir}/gradle/gradle-checkstyle.gradle"
apply from: "${rootDir}/gradle/gradle-tests-staticblockremover.gradle"
+apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle"
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index eb77a3ecb9..a49ef47674 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.mapbox.mapboxsdk
-VERSION_NAME=6.1.4-SNAPSHOT
+VERSION_NAME=6.2.0-SNAPSHOT
POM_DESCRIPTION=Mapbox GL Android SDK
POM_URL=https://github.com/mapbox/mapbox-gl-native
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 858c1eed67..a809460375 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
@@ -5,13 +5,14 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.text.TextUtils;
-
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
import com.mapbox.mapboxsdk.maps.Telemetry;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import timber.log.Timber;
/**
* The entry point to initialize the Mapbox Android SDK.
@@ -33,7 +34,7 @@ public final class Mapbox {
/**
* Get an instance of Mapbox.
* <p>
- * This class manages the active access token, application context, and connectivity state.
+ * This class manages the Mapbox access token, application context, and connectivity state.
* </p>
*
* @param context Android context which holds or is an application context
@@ -41,19 +42,19 @@ public final class Mapbox {
* @return the single instance of Mapbox
*/
@UiThread
- public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull String accessToken) {
+ public static synchronized Mapbox getInstance(@NonNull Context context, @Nullable String accessToken) {
if (INSTANCE == null) {
Context appContext = context.getApplicationContext();
INSTANCE = new Mapbox(appContext, accessToken);
-
- Telemetry.initialize();
+ if (isAccessTokenValid(accessToken)) {
+ initializeTelemetry();
+ }
ConnectivityReceiver.instance(appContext);
}
-
return INSTANCE;
}
- Mapbox(@NonNull Context context, @NonNull String accessToken) {
+ Mapbox(@NonNull Context context, @Nullable String accessToken) {
this.context = context;
this.accessToken = accessToken;
}
@@ -63,40 +64,20 @@ public final class Mapbox {
*
* @return Mapbox access token
*/
+ @Nullable
public static String getAccessToken() {
validateMapbox();
- validateAccessToken();
return INSTANCE.accessToken;
}
/**
- * Runtime validation of Mapbox creation.
- */
- private static void validateMapbox() throws MapboxConfigurationException {
- if (INSTANCE == null) {
- throw new MapboxConfigurationException();
- }
- }
-
- /**
- * Runtime validation of access token.
- *
- * @throws MapboxConfigurationException exception thrown when not using a valid accessToken
- */
- private static void validateAccessToken() throws MapboxConfigurationException {
- String accessToken = INSTANCE.accessToken;
- if (TextUtils.isEmpty(accessToken) || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.")
- && !accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("sk."))) {
- throw new MapboxConfigurationException();
- }
- }
-
- /**
* Application context
*
* @return the application context
*/
+ @NonNull
public static Context getApplicationContext() {
+ validateMapbox();
return INSTANCE.context;
}
@@ -108,6 +89,7 @@ public final class Mapbox {
* disconnected, and null for ConnectivityManager to determine.
*/
public static synchronized void setConnected(Boolean connected) {
+ validateMapbox();
// Connectivity state overridden by app
INSTANCE.connected = connected;
}
@@ -119,6 +101,7 @@ public final class Mapbox {
* @return true if there is an internet connection, false otherwise
*/
public static synchronized Boolean isConnected() {
+ validateMapbox();
if (INSTANCE.connected != null) {
// Connectivity state overridden by app
return INSTANCE.connected;
@@ -128,4 +111,35 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
+
+ /**
+ * Initializes telemetry
+ */
+ private static void initializeTelemetry() {
+ try {
+ Telemetry.initialize();
+ } catch (Exception exception) {
+ Timber.e(exception);
+ }
+ }
+
+ /**
+ * Runtime validation of Mapbox creation.
+ */
+ private static void validateMapbox() {
+ if (INSTANCE == null) {
+ throw new MapboxConfigurationException();
+ }
+ }
+
+ /**
+ * Runtime validation of Mapbox access token
+ *
+ * @param accessToken the access token to validate
+ * @return true is valid, false otherwise
+ */
+ private static boolean isAccessTokenValid(String accessToken) {
+ return !(TextUtils.isEmpty(accessToken)
+ || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.")));
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java
new file mode 100644
index 0000000000..32e852d31b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/CalledFromWorkerThreadException.java
@@ -0,0 +1,8 @@
+package com.mapbox.mapboxsdk.exceptions;
+
+public class CalledFromWorkerThreadException extends RuntimeException {
+
+ public CalledFromWorkerThreadException(String message) {
+ super(message);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
index e9a0261d85..86032aa2b5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
@@ -17,8 +17,8 @@ public class MapboxConfigurationException extends RuntimeException {
* Creates a Mapbox configuration exception thrown by MapboxMap when the SDK hasn't been properly initialised.
*/
public MapboxConfigurationException() {
- super("\nUsing MapView requires setting a valid access token. Use Mapbox.getInstance(Context context, "
- + "String accessToken) to provide one. "
+ super("\nUsing MapView requires calling Mapbox.getInstance(Context context, String accessToken) before "
+ + "inflating or creating the view. The access token parameter is required when using a Mapbox service."
+ "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one."
+ "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens.");
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
index 2b56f5b326..c639e49013 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
@@ -238,6 +238,7 @@ public class LatLngBounds implements Parcelable {
westLon = temp;
}
} else {
+ lonSpan = GeometryConstants.LONGITUDE_SPAN - lonSpan;
if (westLon < eastLon) {
double temp = eastLon;
eastLon = westLon;
@@ -293,6 +294,20 @@ public class LatLngBounds implements Parcelable {
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
double lonWest) {
+ checkParams(latNorth, lonEast, latSouth, lonWest);
+
+ lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
+ }
+
+ private static void checkParams(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latNorth,
+ double lonEast,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
+ double lonWest) {
+
if (Double.isNaN(latNorth) || Double.isNaN(latSouth)) {
throw new IllegalArgumentException("latitude must not be NaN");
}
@@ -313,11 +328,6 @@ public class LatLngBounds implements Parcelable {
if (latNorth < latSouth) {
throw new IllegalArgumentException("LatSouth cannot be less than latNorth");
}
-
- lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
- lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
-
- return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
}
private static double lat_(int z, int y) {
@@ -394,7 +404,7 @@ public class LatLngBounds implements Parcelable {
return (longitude <= eastLon)
&& (longitude >= westLon);
}
- return (longitude < eastLon) || (longitude > westLon);
+ return (longitude <= eastLon) || (longitude >= westLon);
}
/**
@@ -425,36 +435,94 @@ public class LatLngBounds implements Parcelable {
* @param bounds LatLngBounds to add
* @return LatLngBounds
*/
- public LatLngBounds union(LatLngBounds bounds) {
- return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
+ public @NonNull LatLngBounds union(@NonNull LatLngBounds bounds) {
+ return unionNoParamCheck(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
}
/**
* Returns a new LatLngBounds that stretches to include another LatLngBounds,
* given by corner points.
+ * <p>
+ * This values of northLat and southLat should be in the range of [-90, 90],
+ * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
+ * otherwise IllegalArgumentException will be thrown.
+ * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
+ * <p>
+ * This method doesn't recalculate most east or most west boundaries.
+ * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
+ * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
*
- * @param latNorth Northern Latitude
- * @param lonEast Eastern Longitude
- * @param latSouth Southern Latitude
- * @param lonWest Western Longitude
- * @return BoundingBox
- */
- public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) {
- double north = (this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth;
- double south = (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth;
-
- if (LatLngSpan.getLongitudeSpan(lonEast, this.longitudeWest)
- < LatLngSpan.getLongitudeSpan(this.longitudeEast, lonWest)) {
- return new LatLngBounds(north,
- lonEast,
- south,
+ * @param northLat Northern Latitude corner point
+ * @param eastLon Eastern Longitude corner point
+ * @param southLat Southern Latitude corner point
+ * @param westLon Western Longitude corner point
+ * @return LatLngBounds
+ */
+ public @NonNull LatLngBounds union(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ checkParams(northLat, eastLon, southLat, westLon);
+
+ return unionNoParamCheck(northLat, eastLon, southLat, westLon);
+ }
+
+ private @NonNull LatLngBounds unionNoParamCheck(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ northLat = (this.latitudeNorth < northLat) ? northLat : this.latitudeNorth;
+ southLat = (this.latitudeSouth > southLat) ? southLat : this.latitudeSouth;
+
+ eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ // longitudes match
+ if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
+ }
+
+ boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
+ boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
+ boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
+ boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
+
+ // two intersections on each end - covers entire longitude
+ if (eastInThis && westInThis && thisEastInside && thisWestInside) {
+ return new LatLngBounds(northLat, GeometryConstants.MAX_LONGITUDE, southLat, GeometryConstants.MIN_LONGITUDE);
+ }
+
+ if (eastInThis) {
+ if (westInThis) {
+ return new LatLngBounds(northLat, this.longitudeEast, southLat, this.longitudeWest);
+ }
+ return new LatLngBounds(northLat, this.longitudeEast, southLat, westLon);
+ }
+
+ if (thisEastInside) {
+ if (thisWestInside) {
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
+ }
+ return new LatLngBounds(northLat, eastLon, southLat, this.longitudeWest);
+ }
+
+ // bounds do not intersect, find where they will form shortest union
+ if (LatLngSpan.getLongitudeSpan(eastLon, this.longitudeWest)
+ < LatLngSpan.getLongitudeSpan(this.longitudeEast, westLon)) {
+ return new LatLngBounds(northLat,
+ eastLon,
+ southLat,
this.longitudeWest);
}
- return new LatLngBounds(north,
+ return new LatLngBounds(northLat,
this.longitudeEast,
- south,
- lonWest);
+ southLat,
+ westLon);
}
/**
@@ -463,32 +531,89 @@ public class LatLngBounds implements Parcelable {
* @param box LatLngBounds to intersect with
* @return LatLngBounds
*/
- @Nullable
- public LatLngBounds intersect(LatLngBounds box) {
- double minLonWest = Math.max(getLonWest(), box.getLonWest());
- double maxLonEast = Math.min(getLonEast(), box.getLonEast());
- if (maxLonEast > minLonWest) {
- double minLatSouth = Math.max(getLatSouth(), box.getLatSouth());
- double maxLatNorth = Math.min(getLatNorth(), box.getLatNorth());
- if (maxLatNorth > minLatSouth) {
- return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest);
- }
- }
- return null;
+ public @Nullable LatLngBounds intersect(@NonNull LatLngBounds box) {
+ return intersectNoParamCheck(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest());
}
/**
* Returns a new LatLngBounds that is the intersection of this with another LatLngBounds
+ * <p>
+ * This values of northLat and southLat should be in the range of [-90, 90],
+ * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
+ * otherwise IllegalArgumentException will be thrown.
+ * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
+ * <p>
+ * This method doesn't recalculate most east or most west boundaries.
+ * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
+ * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
*
- * @param northLatitude Northern Longitude
- * @param eastLongitude Eastern Latitude
- * @param southLatitude Southern Longitude
- * @param westLongitude Western Latitude
+ * @param northLat Northern Latitude corner point
+ * @param eastLon Eastern Longitude corner point
+ * @param southLat Southern Latitude corner point
+ * @param westLon Western Longitude corner point
* @return LatLngBounds
*/
- public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude,
- double westLongitude) {
- return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude));
+ public @Nullable LatLngBounds intersect(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ checkParams(northLat, eastLon, southLat, westLon);
+
+ return intersectNoParamCheck(northLat, eastLon, southLat, westLon);
+ }
+
+ private @Nullable LatLngBounds intersectNoParamCheck(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ double maxsouthLat = Math.max(getLatSouth(), Math.min(GeometryConstants.MAX_LATITUDE, southLat));
+ double minnorthLat = Math.min(getLatNorth(), Math.max(GeometryConstants.MIN_LATITUDE, northLat));
+ if (minnorthLat < maxsouthLat) {
+ return null;
+ }
+
+ eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ // longitudes match
+ if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
+ }
+
+ boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
+ boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
+ boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
+ boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
+
+ // two intersections : find the one that has longest span
+ if (eastInThis && westInThis && thisEastInside && thisWestInside) {
+
+ if (getLongitudeSpan(eastLon, this.longitudeWest) > getLongitudeSpan(this.longitudeEast, westLon)) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
+ }
+
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
+ }
+
+ if (eastInThis) {
+ if (westInThis) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
+ }
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
+ }
+
+ if (thisEastInside) {
+ if (thisWestInside) {
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, this.longitudeWest);
+ }
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
+ }
+
+ return null;
}
/**
@@ -517,7 +642,7 @@ public class LatLngBounds implements Parcelable {
return (int) ((latitudeNorth + 90)
+ ((latitudeSouth + 90) * 1000)
+ ((longitudeEast + 180) * 1000000)
- + ((longitudeEast + 180) * 1000000000));
+ + ((longitudeWest + 180) * 1000000000));
}
/**
@@ -545,11 +670,11 @@ public class LatLngBounds implements Parcelable {
}
private static LatLngBounds readFromParcel(final Parcel in) {
- final double lonNorth = in.readDouble();
- final double latEast = in.readDouble();
- final double lonSouth = in.readDouble();
- final double latWest = in.readDouble();
- return new LatLngBounds(lonNorth, latEast, lonSouth, latWest);
+ final double northLat = in.readDouble();
+ final double eastLon = in.readDouble();
+ final double southLat = in.readDouble();
+ final double westLon = in.readDouble();
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
index ab1191c0cc..d0e51f941f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.http;
-
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Build;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
index 5fcf206a5a..280877d61a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
@@ -8,7 +8,6 @@ import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import com.mapbox.mapboxsdk.utils.MapFragmentUtils;
import java.util.ArrayList;
@@ -31,6 +30,7 @@ import java.util.List;
public final class MapFragment extends Fragment implements OnMapReadyCallback {
private final List<OnMapReadyCallback> mapReadyCallbackList = new ArrayList<>();
+ private OnMapViewReadyCallback mapViewReadyCallback;
private MapboxMap mapboxMap;
private MapView map;
@@ -56,6 +56,19 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback {
}
/**
+ * Called when the context attaches to this fragment.
+ *
+ * @param context the context attaching
+ */
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof OnMapViewReadyCallback) {
+ mapViewReadyCallback = (OnMapViewReadyCallback) context;
+ }
+ }
+
+ /**
* Creates the fragment view hierarchy.
*
* @param inflater Inflater used to inflate content.
@@ -75,15 +88,25 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback {
* Called when the fragment view hierarchy is created.
*
* @param view The content view of the fragment
- * @param savedInstanceState THe saved instance state of the framgnt
+ * @param savedInstanceState The saved instance state of the fragment
*/
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
map.getMapAsync(this);
+
+ // notify listeners about mapview creation
+ if (mapViewReadyCallback != null) {
+ mapViewReadyCallback.onMapViewReady(map);
+ }
}
+ /**
+ * Called when the style of the map has successfully loaded.
+ *
+ * @param mapboxMap The public api controller of the map
+ */
@Override
public void onMapReady(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
@@ -170,4 +193,21 @@ public final class MapFragment extends Fragment implements OnMapReadyCallback {
onMapReadyCallback.onMapReady(mapboxMap);
}
}
+
+ /**
+ * Callback to be invoked when the map fragment has inflated its MapView.
+ * <p>
+ * To use this interface the context hosting the fragment must implement this interface.
+ * That instance will be set as part of Fragment#onAttach(Context context).
+ * </p>
+ */
+ public interface OnMapViewReadyCallback {
+
+ /**
+ * Called when the map has been created.
+ *
+ * @param mapView The created mapview
+ */
+ void onMapViewReady(MapView mapView);
+ }
}
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 b9f220af1a..3227cb0dab 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
@@ -23,7 +23,6 @@ import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ZoomButtonsController;
-
import com.mapbox.android.gestures.AndroidGesturesManager;
import com.mapbox.android.telemetry.AppUserTurnstile;
import com.mapbox.android.telemetry.Event;
@@ -33,6 +32,8 @@ import com.mapbox.mapboxsdk.BuildConfig;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
@@ -40,9 +41,13 @@ import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer
import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition;
+import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition;
import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -51,9 +56,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION;
import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE;
@@ -537,6 +539,35 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
nativeMapView.setStyleUrl(url);
}
+ /**
+ * Loads a new style from the specified offline region definition and moves the map camera to that region.
+ *
+ * @param definition the offline region definition
+ * @see OfflineRegionDefinition
+ */
+ public void setOfflineRegionDefinition(OfflineRegionDefinition definition) {
+ if (destroyed) {
+ return;
+ }
+
+ OfflineTilePyramidRegionDefinition regionDefinition = (OfflineTilePyramidRegionDefinition) definition;
+ setStyleUrl(regionDefinition.getStyleURL());
+ CameraPosition cameraPosition = new CameraPosition.Builder()
+ .target(regionDefinition.getBounds().getCenter())
+ .zoom(regionDefinition.getMinZoom())
+ .build();
+
+ if (!isMapInitialized()) {
+ mapboxMapOptions.camera(cameraPosition);
+ mapboxMapOptions.minZoomPreference(regionDefinition.getMinZoom());
+ mapboxMapOptions.maxZoomPreference(regionDefinition.getMaxZoom());
+ return;
+ }
+ mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
+ mapboxMap.setMinZoomPreference(regionDefinition.getMinZoom());
+ mapboxMap.setMaxZoomPreference(regionDefinition.getMaxZoom());
+ }
+
//
// Rendering
//
@@ -600,10 +631,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
* @param listener The callback that's invoked on every frame rendered to the map view.
* @see MapView#removeOnMapChangedListener(OnMapChangedListener)
*/
- public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
- if (listener != null) {
- onMapChangedListeners.add(listener);
- }
+ public void addOnMapChangedListener(@NonNull OnMapChangedListener listener) {
+ onMapChangedListeners.add(listener);
}
/**
@@ -612,8 +641,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
* @param listener The previously added callback to remove.
* @see MapView#addOnMapChangedListener(OnMapChangedListener)
*/
- public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
- if (listener != null && onMapChangedListeners.contains(listener)) {
+ public void removeOnMapChangedListener(@NonNull OnMapChangedListener listener) {
+ if (onMapChangedListeners.contains(listener)) {
onMapChangedListeners.remove(listener);
}
}
@@ -624,13 +653,11 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
* @param callback The callback object that will be triggered when the map is ready to be used.
*/
@UiThread
- public void getMapAsync(final OnMapReadyCallback callback) {
- if (!mapCallback.isInitialLoad() && callback != null) {
+ public void getMapAsync(final @NonNull OnMapReadyCallback callback) {
+ if (!mapCallback.isInitialLoad()) {
callback.onMapReady(mapboxMap);
} else {
- if (callback != null) {
- mapCallback.addOnMapReadyCallback(callback);
- }
+ mapCallback.addOnMapReadyCallback(callback);
}
}
@@ -883,6 +910,8 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
* {@link #WILL_START_RENDERING_MAP},
* {@link #DID_FINISH_RENDERING_MAP},
* {@link #DID_FINISH_RENDERING_MAP_FULLY_RENDERED}.
+ * {@link #DID_FINISH_LOADING_STYLE},
+ * {@link #SOURCE_DID_CHANGE}.
*/
void onMapChanged(@MapChange int change);
}
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 cfa7143671..aed918cb79 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
@@ -120,7 +120,7 @@ public final class MapboxMap {
*
* @param outState the bundle to save the state to.
*/
- void onSaveInstanceState(Bundle outState) {
+ void onSaveInstanceState(@NonNull Bundle outState) {
outState.putParcelable(MapboxConstants.STATE_CAMERA_POSITION, transform.getCameraPosition());
outState.putBoolean(MapboxConstants.STATE_DEBUG_ACTIVE, nativeMapView.getDebug());
outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl());
@@ -132,7 +132,7 @@ public final class MapboxMap {
*
* @param savedInstanceState the bundle containing the saved state
*/
- void onRestoreInstanceState(Bundle savedInstanceState) {
+ void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION);
uiSettings.onRestoreInstanceState(savedInstanceState);
@@ -266,6 +266,7 @@ public final class MapboxMap {
*
* @return all the layers in the current style
*/
+ @NonNull
public List<Layer> getLayers() {
return nativeMapView.getLayers();
}
@@ -377,6 +378,7 @@ public final class MapboxMap {
*
* @return all the sources in the current style
*/
+ @NonNull
public List<Source> getSources() {
return nativeMapView.getSources();
}
@@ -463,10 +465,11 @@ public final class MapboxMap {
*
* @param name the name of the image to remove
*/
- public void removeImage(String name) {
+ public void removeImage(@NonNull String name) {
nativeMapView.removeImage(name);
}
+ @Nullable
public Bitmap getImage(@NonNull String name) {
return nativeMapView.getImage(name);
}
@@ -537,6 +540,7 @@ public final class MapboxMap {
*
* @return the UiSettings associated with this map
*/
+ @NonNull
public UiSettings getUiSettings() {
return uiSettings;
}
@@ -551,6 +555,7 @@ public final class MapboxMap {
*
* @return the Projection associated with this map
*/
+ @NonNull
public Projection getProjection() {
return projection;
}
@@ -564,7 +569,7 @@ public final class MapboxMap {
*
* @return the global light source
*/
- @Nullable
+ @NonNull
public Light getLight() {
return nativeMapView.getLight();
}
@@ -590,6 +595,7 @@ public final class MapboxMap {
*
* @return The current position of the Camera.
*/
+ @NonNull
public final CameraPosition getCameraPosition() {
return transform.getCameraPosition();
}
@@ -612,7 +618,7 @@ public final class MapboxMap {
*
* @param update The change that should be applied to the camera.
*/
- public final void moveCamera(CameraUpdate update) {
+ public final void moveCamera(@NonNull CameraUpdate update) {
moveCamera(update, null);
}
@@ -624,7 +630,8 @@ public final class MapboxMap {
* @param update The change that should be applied to the camera
* @param callback the callback to be invoked when an animation finishes or is canceled
*/
- public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) {
+ public final void moveCamera(@NonNull final CameraUpdate update,
+ @Nullable final MapboxMap.CancelableCallback callback) {
transform.moveCamera(MapboxMap.this, update, callback);
}
@@ -650,7 +657,7 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void easeCamera(CameraUpdate update, int durationMs) {
+ public final void easeCamera(@NonNull CameraUpdate update, int durationMs) {
easeCamera(update, durationMs, null);
}
@@ -673,7 +680,8 @@ public final class MapboxMap {
* Do not update or ease the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
+ public final void easeCamera(@NonNull CameraUpdate update, int durationMs,
+ @Nullable final MapboxMap.CancelableCallback callback) {
easeCamera(update, durationMs, true, callback);
}
@@ -691,7 +699,7 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @param easingInterpolator True for easing interpolator, false for linear.
*/
- public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) {
+ public final void easeCamera(@NonNull CameraUpdate update, int durationMs, boolean easingInterpolator) {
easeCamera(update, durationMs, easingInterpolator, null);
}
@@ -711,8 +719,10 @@ public final class MapboxMap {
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or ease the camera from within onCancel().
*/
- public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
- final MapboxMap.CancelableCallback callback) {
+ public final void easeCamera(@NonNull final CameraUpdate update,
+ final int durationMs,
+ final boolean easingInterpolator,
+ @Nullable final MapboxMap.CancelableCallback callback) {
easeCamera(update, durationMs, easingInterpolator, callback, false);
}
@@ -733,8 +743,9 @@ public final class MapboxMap {
* Do not update or ease the camera from within onCancel().
* @param isDismissable true will allow animated camera changes dismiss a tracking mode.
*/
- public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
- final MapboxMap.CancelableCallback callback, final boolean isDismissable) {
+ public final void easeCamera(@NonNull final CameraUpdate update, final int durationMs,
+ final boolean easingInterpolator, @Nullable final MapboxMap.CancelableCallback callback,
+ final boolean isDismissable) {
if (durationMs <= 0) {
throw new IllegalArgumentException("Null duration passed into easeCamera");
@@ -751,7 +762,7 @@ public final class MapboxMap {
* @param update The change that should be applied to the camera.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void animateCamera(CameraUpdate update) {
+ public final void animateCamera(@NonNull CameraUpdate update) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, null);
}
@@ -767,7 +778,7 @@ public final class MapboxMap {
* called. Do not update or animate the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
+ public final void animateCamera(@NonNull CameraUpdate update, @Nullable MapboxMap.CancelableCallback callback) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback);
}
@@ -782,7 +793,7 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void animateCamera(CameraUpdate update, int durationMs) {
+ public final void animateCamera(@NonNull CameraUpdate update, int durationMs) {
animateCamera(update, durationMs, null);
}
@@ -804,8 +815,8 @@ public final class MapboxMap {
* isn't required, leave it as null.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- public final void animateCamera(final CameraUpdate update, final int durationMs,
- final MapboxMap.CancelableCallback callback) {
+ public final void animateCamera(@NonNull final CameraUpdate update, final int durationMs,
+ @Nullable final MapboxMap.CancelableCallback callback) {
if (durationMs <= 0) {
throw new IllegalArgumentException("Null duration passed into animageCamera");
}
@@ -1069,6 +1080,7 @@ public final class MapboxMap {
*
* @return The json of the map style
*/
+ @NonNull
public String getStyleJson() {
return nativeMapView.getStyleJson();
}
@@ -1232,7 +1244,7 @@ public final class MapboxMap {
*
* @param polyline An updated polyline object.
*/
- public void updatePolyline(Polyline polyline) {
+ public void updatePolyline(@NonNull Polyline polyline) {
annotationManager.updatePolyline(polyline);
}
@@ -1263,7 +1275,7 @@ public final class MapboxMap {
*
* @param polygon An updated polygon object
*/
- public void updatePolygon(Polygon polygon) {
+ public void updatePolygon(@NonNull Polygon polygon) {
annotationManager.updatePolygon(polygon);
}
@@ -1468,6 +1480,7 @@ public final class MapboxMap {
*
* @return The currently selected marker.
*/
+ @NonNull
public List<Marker> getSelectedMarkers() {
return annotationManager.getSelectedMarkers();
}
@@ -1477,6 +1490,7 @@ public final class MapboxMap {
*
* @return the associated MarkerViewManager
*/
+ @NonNull
public MarkerViewManager getMarkerViewManager() {
return annotationManager.getMarkerViewManager();
}
@@ -1550,6 +1564,7 @@ public final class MapboxMap {
* @param padding the padding to apply to the bounds
* @return the camera position that fits the bounds and padding
*/
+ @NonNull
public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, int[] padding) {
// get padded camera position from LatLngBounds
return nativeMapView.getCameraForLatLngBounds(latLngBounds, padding);
@@ -1563,6 +1578,7 @@ public final class MapboxMap {
* @param padding the padding to apply to the bounds
* @return the camera position that fits the bounds and padding
*/
+ @NonNull
public CameraPosition getCameraForGeometry(Geometry geometry, double bearing, int[] padding) {
// get padded camera position from Geometry
return nativeMapView.getCameraForGeometry(geometry, bearing, padding);
@@ -1591,11 +1607,7 @@ public final class MapboxMap {
* @param bottom The bottom margin in pixels.
*/
public void setPadding(int left, int top, int right, int bottom) {
- setPadding(new int[] {left, top, right, bottom});
- }
-
- private void setPadding(int[] padding) {
- projection.setContentPadding(padding);
+ projection.setContentPadding(new int[] {left, top, right, bottom});
uiSettings.invalidate();
}
@@ -1604,6 +1616,7 @@ public final class MapboxMap {
*
* @return An array with length 4 in the LTRB order.
*/
+ @NonNull
public int[] getPadding() {
return projection.getContentPadding();
}
@@ -1755,6 +1768,7 @@ public final class MapboxMap {
}
// used by MapView
+ @Nullable
OnFpsChangedListener getOnFpsChangedListener() {
return onFpsChangedListener;
}
@@ -1902,7 +1916,7 @@ public final class MapboxMap {
* will be added to the passed gestures manager.
* @see <a href="https://github.com/mapbox/mapbox-gestures-android">mapbox-gestures-android library</a>
*/
- public void setGesturesManager(AndroidGesturesManager androidGesturesManager, boolean attachDefaultListeners,
+ public void setGesturesManager(@NonNull AndroidGesturesManager androidGesturesManager, boolean attachDefaultListeners,
boolean setDefaultMutuallyExclusives) {
onGesturesManagerInteractionListener.setGesturesManager(
androidGesturesManager, attachDefaultListeners, setDefaultMutuallyExclusives);
@@ -1914,6 +1928,7 @@ public final class MapboxMap {
*
* @return Current gestures manager.
*/
+ @NonNull
public AndroidGesturesManager getGesturesManager() {
return onGesturesManagerInteractionListener.getGesturesManager();
}
@@ -2000,6 +2015,7 @@ public final class MapboxMap {
*
* @return Current active InfoWindow Click Listener
*/
+ @Nullable
public OnInfoWindowClickListener getOnInfoWindowClickListener() {
return annotationManager.getInfoWindowManager().getOnInfoWindowClickListener();
}
@@ -2020,6 +2036,7 @@ public final class MapboxMap {
*
* @return Current active InfoWindow long Click Listener
*/
+ @Nullable
public OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() {
return annotationManager.getInfoWindowManager().getOnInfoWindowLongClickListener();
}
@@ -2038,6 +2055,7 @@ public final class MapboxMap {
*
* @return Current active InfoWindow Close Listener
*/
+ @Nullable
public OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
return annotationManager.getInfoWindowManager().getOnInfoWindowCloseListener();
}
@@ -2147,11 +2165,11 @@ public final class MapboxMap {
* @see MapboxMap#addOnMoveListener(OnMoveListener)
*/
public interface OnMoveListener {
- void onMoveBegin(MoveGestureDetector detector);
+ void onMoveBegin(@NonNull MoveGestureDetector detector);
- void onMove(MoveGestureDetector detector);
+ void onMove(@NonNull MoveGestureDetector detector);
- void onMoveEnd(MoveGestureDetector detector);
+ void onMoveEnd(@NonNull MoveGestureDetector detector);
}
/**
@@ -2160,11 +2178,11 @@ public final class MapboxMap {
* @see MapboxMap#addOnRotateListener(OnRotateListener)
*/
public interface OnRotateListener {
- void onRotateBegin(RotateGestureDetector detector);
+ void onRotateBegin(@NonNull RotateGestureDetector detector);
- void onRotate(RotateGestureDetector detector);
+ void onRotate(@NonNull RotateGestureDetector detector);
- void onRotateEnd(RotateGestureDetector detector);
+ void onRotateEnd(@NonNull RotateGestureDetector detector);
}
/**
@@ -2173,11 +2191,11 @@ public final class MapboxMap {
* @see MapboxMap#addOnScaleListener(OnScaleListener)
*/
public interface OnScaleListener {
- void onScaleBegin(StandardScaleGestureDetector detector);
+ void onScaleBegin(@NonNull StandardScaleGestureDetector detector);
- void onScale(StandardScaleGestureDetector detector);
+ void onScale(@NonNull StandardScaleGestureDetector detector);
- void onScaleEnd(StandardScaleGestureDetector detector);
+ void onScaleEnd(@NonNull StandardScaleGestureDetector detector);
}
/**
@@ -2186,11 +2204,11 @@ public final class MapboxMap {
* @see MapboxMap#addOnShoveListener(OnShoveListener)
*/
public interface OnShoveListener {
- void onShoveBegin(ShoveGestureDetector detector);
+ void onShoveBegin(@NonNull ShoveGestureDetector detector);
- void onShove(ShoveGestureDetector detector);
+ void onShove(@NonNull ShoveGestureDetector detector);
- void onShoveEnd(ShoveGestureDetector detector);
+ void onShoveEnd(@NonNull ShoveGestureDetector detector);
}
/**
@@ -2442,7 +2460,7 @@ public final class MapboxMap {
*
* @param marker The marker were the info window is attached to
*/
- void onInfoWindowLongClick(Marker marker);
+ void onInfoWindowLongClick(@NonNull Marker marker);
}
/**
@@ -2457,7 +2475,7 @@ public final class MapboxMap {
*
* @param marker The marker of the info window that was closed.
*/
- void onInfoWindowClose(Marker marker);
+ void onInfoWindowClose(@NonNull Marker marker);
}
/**
@@ -2637,7 +2655,7 @@ public final class MapboxMap {
*
* @param snapshot the snapshot bitmap
*/
- void onSnapshotReady(Bitmap snapshot);
+ void onSnapshotReady(@NonNull Bitmap snapshot);
}
/**
@@ -2649,12 +2667,13 @@ public final class MapboxMap {
*
* @param style the style that has been loaded
*/
- void onStyleLoaded(String style);
+ void onStyleLoaded(@NonNull String style);
}
//
// Used for instrumentation testing
//
+ @NonNull
Transform getTransform() {
return transform;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index c84651da24..d72e1a74a9 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
@@ -11,7 +11,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
-
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.Geometry;
import com.mapbox.mapboxsdk.LibraryLoader;
@@ -20,6 +19,7 @@ import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.exceptions.CalledFromWorkerThreadException;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
@@ -32,6 +32,7 @@ import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
+import timber.log.Timber;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -41,8 +42,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
-import timber.log.Timber;
-
// Class that wraps the native methods for convenience
final class NativeMapView {
@@ -52,6 +51,9 @@ final class NativeMapView {
// Used to schedule work on the MapRenderer Thread
private final MapRenderer mapRenderer;
+ // Used to validate if methods are called from the correct thread
+ private final Thread thread;
+
// Used for callbacks
private ViewCallback viewCallback;
@@ -87,6 +89,7 @@ final class NativeMapView {
this.viewCallback = viewCallback;
this.fileSource = FileSource.getInstance(context);
this.pixelRatio = pixelRatio;
+ this.thread = Thread.currentThread();
nativeInitialize(this, fileSource, mapRenderer, pixelRatio);
}
@@ -94,7 +97,17 @@ final class NativeMapView {
// Methods
//
- private boolean isDestroyedOn(String callingMethod) {
+ private boolean checkState(String callingMethod) {
+ // validate if invocation has occurred on the main thread
+ if (thread != Thread.currentThread()) {
+ throw new CalledFromWorkerThreadException(
+ String.format(
+ "Map interactions should happen on the UI thread. Method invoked from wrong thread is %s.",
+ callingMethod)
+ );
+ }
+
+ // validate if map has already been destroyed
if (destroyed && !TextUtils.isEmpty(callingMethod)) {
Timber.e(
"You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?",
@@ -112,7 +125,7 @@ final class NativeMapView {
}
public void update() {
- if (isDestroyedOn("update")) {
+ if (checkState("update")) {
return;
}
@@ -120,7 +133,7 @@ final class NativeMapView {
}
public void resizeView(int width, int height) {
- if (isDestroyedOn("resizeView")) {
+ if (checkState("resizeView")) {
return;
}
width = (int) (width / pixelRatio);
@@ -152,84 +165,84 @@ final class NativeMapView {
}
public void setStyleUrl(String url) {
- if (isDestroyedOn("setStyleUrl")) {
+ if (checkState("setStyleUrl")) {
return;
}
nativeSetStyleUrl(url);
}
public String getStyleUrl() {
- if (isDestroyedOn("getStyleUrl")) {
+ if (checkState("getStyleUrl")) {
return null;
}
return nativeGetStyleUrl();
}
public void setStyleJson(String newStyleJson) {
- if (isDestroyedOn("setStyleJson")) {
+ if (checkState("setStyleJson")) {
return;
}
nativeSetStyleJson(newStyleJson);
}
public String getStyleJson() {
- if (isDestroyedOn("getStyleJson")) {
+ if (checkState("getStyleJson")) {
return null;
}
return nativeGetStyleJson();
}
public void setLatLngBounds(LatLngBounds latLngBounds) {
- if (isDestroyedOn("setLatLngBounds")) {
+ if (checkState("setLatLngBounds")) {
return;
}
nativeSetLatLngBounds(latLngBounds);
}
public void cancelTransitions() {
- if (isDestroyedOn("cancelTransitions")) {
+ if (checkState("cancelTransitions")) {
return;
}
nativeCancelTransitions();
}
public void setGestureInProgress(boolean inProgress) {
- if (isDestroyedOn("setGestureInProgress")) {
+ if (checkState("setGestureInProgress")) {
return;
}
nativeSetGestureInProgress(inProgress);
}
public void moveBy(double dx, double dy) {
- if (isDestroyedOn("moveBy")) {
+ if (checkState("moveBy")) {
return;
}
moveBy(dx, dy, 0);
}
public void moveBy(double dx, double dy, long duration) {
- if (isDestroyedOn("moveBy")) {
+ if (checkState("moveBy")) {
return;
}
nativeMoveBy(dx / pixelRatio, dy / pixelRatio, duration);
}
public void setLatLng(LatLng latLng) {
- if (isDestroyedOn("setLatLng")) {
+ if (checkState("setLatLng")) {
return;
}
setLatLng(latLng, 0);
}
public void setLatLng(LatLng latLng, long duration) {
- if (isDestroyedOn("setLatLng")) {
+ if (checkState("setLatLng")) {
return;
}
nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration);
}
public LatLng getLatLng() {
- if (isDestroyedOn("")) {
+ if (checkState("")) {
return new LatLng();
}
// wrap longitude values coming from core
@@ -237,7 +250,7 @@ final class NativeMapView {
}
public CameraPosition getCameraForLatLngBounds(LatLngBounds latLngBounds, int[] padding) {
- if (isDestroyedOn("getCameraForLatLngBounds")) {
+ if (checkState("getCameraForLatLngBounds")) {
return null;
}
return nativeGetCameraForLatLngBounds(
@@ -249,7 +262,7 @@ final class NativeMapView {
}
public CameraPosition getCameraForGeometry(Geometry geometry, double bearing, int[] padding) {
- if (isDestroyedOn("getCameraForGeometry")) {
+ if (checkState("getCameraForGeometry")) {
return null;
}
return nativeGetCameraForGeometry(
@@ -261,77 +274,77 @@ final class NativeMapView {
}
public void resetPosition() {
- if (isDestroyedOn("resetPosition")) {
+ if (checkState("resetPosition")) {
return;
}
nativeResetPosition();
}
public double getPitch() {
- if (isDestroyedOn("getPitch")) {
+ if (checkState("getPitch")) {
return 0;
}
return nativeGetPitch();
}
public void setPitch(double pitch, long duration) {
- if (isDestroyedOn("setPitch")) {
+ if (checkState("setPitch")) {
return;
}
nativeSetPitch(pitch, duration);
}
public void setZoom(double zoom, PointF focalPoint, long duration) {
- if (isDestroyedOn("setZoom")) {
+ if (checkState("setZoom")) {
return;
}
nativeSetZoom(zoom, focalPoint.x / pixelRatio, focalPoint.y / pixelRatio, duration);
}
public double getZoom() {
- if (isDestroyedOn("getZoom")) {
+ if (checkState("getZoom")) {
return 0;
}
return nativeGetZoom();
}
public void resetZoom() {
- if (isDestroyedOn("resetZoom")) {
+ if (checkState("resetZoom")) {
return;
}
nativeResetZoom();
}
public void setMinZoom(double zoom) {
- if (isDestroyedOn("setMinZoom")) {
+ if (checkState("setMinZoom")) {
return;
}
nativeSetMinZoom(zoom);
}
public double getMinZoom() {
- if (isDestroyedOn("getMinZoom")) {
+ if (checkState("getMinZoom")) {
return 0;
}
return nativeGetMinZoom();
}
public void setMaxZoom(double zoom) {
- if (isDestroyedOn("setMaxZoom")) {
+ if (checkState("setMaxZoom")) {
return;
}
nativeSetMaxZoom(zoom);
}
public double getMaxZoom() {
- if (isDestroyedOn("getMaxZoom")) {
+ if (checkState("getMaxZoom")) {
return 0;
}
return nativeGetMaxZoom();
}
public void rotateBy(double sx, double sy, double ex, double ey) {
- if (isDestroyedOn("rotateBy")) {
+ if (checkState("rotateBy")) {
return;
}
rotateBy(sx, sy, ex, ey, 0);
@@ -339,14 +352,14 @@ final class NativeMapView {
public void rotateBy(double sx, double sy, double ex, double ey,
long duration) {
- if (isDestroyedOn("rotateBy")) {
+ if (checkState("rotateBy")) {
return;
}
nativeRotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey, duration);
}
public void setContentPadding(int[] padding) {
- if (isDestroyedOn("setContentPadding")) {
+ if (checkState("setContentPadding")) {
return;
}
nativeSetContentPadding(
@@ -357,49 +370,49 @@ final class NativeMapView {
}
public void setBearing(double degrees) {
- if (isDestroyedOn("setBearing")) {
+ if (checkState("setBearing")) {
return;
}
setBearing(degrees, 0);
}
public void setBearing(double degrees, long duration) {
- if (isDestroyedOn("setBearing")) {
+ if (checkState("setBearing")) {
return;
}
nativeSetBearing(degrees, duration);
}
public void setBearing(double degrees, double cx, double cy) {
- if (isDestroyedOn("setBearing")) {
+ if (checkState("setBearing")) {
return;
}
setBearing(degrees, cx, cy, 0);
}
public void setBearing(double degrees, double fx, double fy, long duration) {
- if (isDestroyedOn("setBearing")) {
+ if (checkState("setBearing")) {
return;
}
nativeSetBearingXY(degrees, fx / pixelRatio, fy / pixelRatio, duration);
}
public double getBearing() {
- if (isDestroyedOn("getBearing")) {
+ if (checkState("getBearing")) {
return 0;
}
return nativeGetBearing();
}
public void resetNorth() {
- if (isDestroyedOn("resetNorth")) {
+ if (checkState("resetNorth")) {
return;
}
nativeResetNorth();
}
public long addMarker(Marker marker) {
- if (isDestroyedOn("addMarker")) {
+ if (checkState("addMarker")) {
return 0;
}
Marker[] markers = {marker};
@@ -407,14 +420,14 @@ final class NativeMapView {
}
public long[] addMarkers(List<Marker> markers) {
- if (isDestroyedOn("addMarkers")) {
+ if (checkState("addMarkers")) {
return new long[] {};
}
return nativeAddMarkers(markers.toArray(new Marker[markers.size()]));
}
public long addPolyline(Polyline polyline) {
- if (isDestroyedOn("addPolyline")) {
+ if (checkState("addPolyline")) {
return 0;
}
Polyline[] polylines = {polyline};
@@ -422,14 +435,14 @@ final class NativeMapView {
}
public long[] addPolylines(List<Polyline> polylines) {
- if (isDestroyedOn("addPolylines")) {
+ if (checkState("addPolylines")) {
return new long[] {};
}
return nativeAddPolylines(polylines.toArray(new Polyline[polylines.size()]));
}
public long addPolygon(Polygon polygon) {
- if (isDestroyedOn("addPolygon")) {
+ if (checkState("addPolygon")) {
return 0;
}
Polygon[] polygons = {polygon};
@@ -437,14 +450,14 @@ final class NativeMapView {
}
public long[] addPolygons(List<Polygon> polygons) {
- if (isDestroyedOn("addPolygons")) {
+ if (checkState("addPolygons")) {
return new long[] {};
}
return nativeAddPolygons(polygons.toArray(new Polygon[polygons.size()]));
}
public void updateMarker(Marker marker) {
- if (isDestroyedOn("updateMarker")) {
+ if (checkState("updateMarker")) {
return;
}
LatLng position = marker.getPosition();
@@ -453,21 +466,21 @@ final class NativeMapView {
}
public void updatePolygon(Polygon polygon) {
- if (isDestroyedOn("updatePolygon")) {
+ if (checkState("updatePolygon")) {
return;
}
nativeUpdatePolygon(polygon.getId(), polygon);
}
public void updatePolyline(Polyline polyline) {
- if (isDestroyedOn("updatePolyline")) {
+ if (checkState("updatePolyline")) {
return;
}
nativeUpdatePolyline(polyline.getId(), polyline);
}
public void removeAnnotation(long id) {
- if (isDestroyedOn("removeAnnotation")) {
+ if (checkState("removeAnnotation")) {
return;
}
long[] ids = {id};
@@ -475,105 +488,105 @@ final class NativeMapView {
}
public void removeAnnotations(long[] ids) {
- if (isDestroyedOn("removeAnnotations")) {
+ if (checkState("removeAnnotations")) {
return;
}
nativeRemoveAnnotations(ids);
}
public long[] queryPointAnnotations(RectF rect) {
- if (isDestroyedOn("queryPointAnnotations")) {
+ if (checkState("queryPointAnnotations")) {
return new long[] {};
}
return nativeQueryPointAnnotations(rect);
}
public long[] queryShapeAnnotations(RectF rectF) {
- if (isDestroyedOn("queryShapeAnnotations")) {
+ if (checkState("queryShapeAnnotations")) {
return new long[] {};
}
return nativeQueryShapeAnnotations(rectF);
}
public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) {
- if (isDestroyedOn("addAnnotationIcon")) {
+ if (checkState("addAnnotationIcon")) {
return;
}
nativeAddAnnotationIcon(symbol, width, height, scale, pixels);
}
public void removeAnnotationIcon(String symbol) {
- if (isDestroyedOn("removeAnnotationIcon")) {
+ if (checkState("removeAnnotationIcon")) {
return;
}
nativeRemoveAnnotationIcon(symbol);
}
public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
- if (isDestroyedOn("setVisibleCoordinateBounds")) {
+ if (checkState("setVisibleCoordinateBounds")) {
return;
}
nativeSetVisibleCoordinateBounds(coordinates, padding, direction, duration);
}
public void onLowMemory() {
- if (isDestroyedOn("onLowMemory")) {
+ if (checkState("onLowMemory")) {
return;
}
nativeOnLowMemory();
}
public void setDebug(boolean debug) {
- if (isDestroyedOn("setDebug")) {
+ if (checkState("setDebug")) {
return;
}
nativeSetDebug(debug);
}
public void cycleDebugOptions() {
- if (isDestroyedOn("cycleDebugOptions")) {
+ if (checkState("cycleDebugOptions")) {
return;
}
nativeCycleDebugOptions();
}
public boolean getDebug() {
- if (isDestroyedOn("getDebug")) {
+ if (checkState("getDebug")) {
return false;
}
return nativeGetDebug();
}
public boolean isFullyLoaded() {
- if (isDestroyedOn("isFullyLoaded")) {
+ if (checkState("isFullyLoaded")) {
return false;
}
return nativeIsFullyLoaded();
}
public void setReachability(boolean status) {
- if (isDestroyedOn("setReachability")) {
+ if (checkState("setReachability")) {
return;
}
nativeSetReachability(status);
}
public double getMetersPerPixelAtLatitude(double lat) {
- if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
+ if (checkState("getMetersPerPixelAtLatitude")) {
return 0;
}
return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
- if (isDestroyedOn("projectedMetersForLatLng")) {
+ if (checkState("projectedMetersForLatLng")) {
return null;
}
return nativeProjectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude());
}
public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) {
- if (isDestroyedOn("latLngForProjectedMeters")) {
+ if (checkState("latLngForProjectedMeters")) {
return new LatLng();
}
return nativeLatLngForProjectedMeters(projectedMeters.getNorthing(),
@@ -581,7 +594,7 @@ final class NativeMapView {
}
public PointF pixelForLatLng(LatLng latLng) {
- if (isDestroyedOn("pixelForLatLng")) {
+ if (checkState("pixelForLatLng")) {
return new PointF();
}
PointF pointF = nativePixelForLatLng(latLng.getLatitude(), latLng.getLongitude());
@@ -590,21 +603,21 @@ final class NativeMapView {
}
public LatLng latLngForPixel(PointF pixel) {
- if (isDestroyedOn("latLngForPixel")) {
+ if (checkState("latLngForPixel")) {
return new LatLng();
}
return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio).wrap();
}
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
- if (isDestroyedOn("getTopOffsetPixelsForAnnotationSymbol")) {
+ if (checkState("getTopOffsetPixelsForAnnotationSymbol")) {
return 0;
}
return nativeGetTopOffsetPixelsForAnnotationSymbol(symbolName);
}
public void jumpTo(double angle, LatLng center, double pitch, double zoom) {
- if (isDestroyedOn("jumpTo")) {
+ if (checkState("jumpTo")) {
return;
}
nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
@@ -612,7 +625,7 @@ final class NativeMapView {
public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom,
boolean easingInterpolator) {
- if (isDestroyedOn("easeTo")) {
+ if (checkState("easeTo")) {
return;
}
nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
@@ -620,28 +633,28 @@ final class NativeMapView {
}
public void flyTo(double angle, LatLng center, long duration, double pitch, double zoom) {
- if (isDestroyedOn("flyTo")) {
+ if (checkState("flyTo")) {
return;
}
nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
}
public CameraPosition getCameraPosition() {
- if (isDestroyedOn("getCameraValues")) {
+ if (checkState("getCameraValues")) {
return new CameraPosition.Builder().build();
}
return nativeGetCameraPosition();
}
public void setPrefetchesTiles(boolean enable) {
- if (isDestroyedOn("setPrefetchesTiles")) {
+ if (checkState("setPrefetchesTiles")) {
return;
}
nativeSetPrefetchesTiles(enable);
}
public boolean getPrefetchesTiles() {
- if (isDestroyedOn("getPrefetchesTiles")) {
+ if (checkState("getPrefetchesTiles")) {
return false;
}
return nativeGetPrefetchesTiles();
@@ -666,42 +679,42 @@ final class NativeMapView {
}
public List<Layer> getLayers() {
- if (isDestroyedOn("getLayers")) {
+ if (checkState("getLayers")) {
return null;
}
return Arrays.asList(nativeGetLayers());
}
public Layer getLayer(String layerId) {
- if (isDestroyedOn("getLayer")) {
+ if (checkState("getLayer")) {
return null;
}
return nativeGetLayer(layerId);
}
public void addLayer(@NonNull Layer layer) {
- if (isDestroyedOn("addLayer")) {
+ if (checkState("addLayer")) {
return;
}
nativeAddLayer(layer.getNativePtr(), null);
}
public void addLayerBelow(@NonNull Layer layer, @NonNull String below) {
- if (isDestroyedOn("addLayerBelow")) {
+ if (checkState("addLayerBelow")) {
return;
}
nativeAddLayer(layer.getNativePtr(), below);
}
public void addLayerAbove(@NonNull Layer layer, @NonNull String above) {
- if (isDestroyedOn("addLayerAbove")) {
+ if (checkState("addLayerAbove")) {
return;
}
nativeAddLayerAbove(layer.getNativePtr(), above);
}
public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) {
- if (isDestroyedOn("addLayerAt")) {
+ if (checkState("addLayerAt")) {
return;
}
nativeAddLayerAt(layer.getNativePtr(), index);
@@ -709,7 +722,7 @@ final class NativeMapView {
@Nullable
public Layer removeLayer(@NonNull String layerId) {
- if (isDestroyedOn("removeLayer")) {
+ if (checkState("removeLayer")) {
return null;
}
return nativeRemoveLayerById(layerId);
@@ -717,7 +730,7 @@ final class NativeMapView {
@Nullable
public Layer removeLayer(@NonNull Layer layer) {
- if (isDestroyedOn("removeLayer")) {
+ if (checkState("removeLayer")) {
return null;
}
nativeRemoveLayer(layer.getNativePtr());
@@ -726,28 +739,28 @@ final class NativeMapView {
@Nullable
public Layer removeLayerAt(@IntRange(from = 0) int index) {
- if (isDestroyedOn("removeLayerAt")) {
+ if (checkState("removeLayerAt")) {
return null;
}
return nativeRemoveLayerAt(index);
}
public List<Source> getSources() {
- if (isDestroyedOn("getSources")) {
+ if (checkState("getSources")) {
return null;
}
return Arrays.asList(nativeGetSources());
}
public Source getSource(@NonNull String sourceId) {
- if (isDestroyedOn("getSource")) {
+ if (checkState("getSource")) {
return null;
}
return nativeGetSource(sourceId);
}
public void addSource(@NonNull Source source) {
- if (isDestroyedOn("addSource")) {
+ if (checkState("addSource")) {
return;
}
nativeAddSource(source, source.getNativePtr());
@@ -755,7 +768,7 @@ final class NativeMapView {
@Nullable
public Source removeSource(@NonNull String sourceId) {
- if (isDestroyedOn("removeSource")) {
+ if (checkState("removeSource")) {
return null;
}
Source source = getSource(sourceId);
@@ -767,7 +780,7 @@ final class NativeMapView {
@Nullable
public Source removeSource(@NonNull Source source) {
- if (isDestroyedOn("removeSource")) {
+ if (checkState("removeSource")) {
return null;
}
nativeRemoveSource(source, source.getNativePtr());
@@ -775,16 +788,17 @@ final class NativeMapView {
}
public void addImage(@NonNull String name, @NonNull Bitmap image) {
- if (isDestroyedOn("addImage")) {
+ if (checkState("addImage")) {
return;
}
- // Determine pixel ratio
- nativeAddImage(name, image, image.getDensity() / DisplayMetrics.DENSITY_DEFAULT);
+ // Determine pixel ratio, cast to float to avoid rounding, see mapbox-gl-native/issues/11809
+ float pixelRatio = (float) image.getDensity() / DisplayMetrics.DENSITY_DEFAULT;
+ nativeAddImage(name, image, pixelRatio);
}
public void addImages(@NonNull HashMap<String, Bitmap> bitmapHashMap) {
- if (isDestroyedOn("addImages")) {
+ if (checkState("addImages")) {
return;
}
//noinspection unchecked
@@ -792,14 +806,14 @@ final class NativeMapView {
}
public void removeImage(String name) {
- if (isDestroyedOn("removeImage")) {
+ if (checkState("removeImage")) {
return;
}
nativeRemoveImage(name);
}
public Bitmap getImage(String name) {
- if (isDestroyedOn("getImage")) {
+ if (checkState("getImage")) {
return null;
}
return nativeGetImage(name);
@@ -811,7 +825,7 @@ final class NativeMapView {
public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates,
@Nullable String[] layerIds,
@Nullable Expression filter) {
- if (isDestroyedOn("queryRenderedFeatures")) {
+ if (checkState("queryRenderedFeatures")) {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio,
@@ -823,7 +837,7 @@ final class NativeMapView {
public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates,
@Nullable String[] layerIds,
@Nullable Expression filter) {
- if (isDestroyedOn("queryRenderedFeatures")) {
+ if (checkState("queryRenderedFeatures")) {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForBox(
@@ -837,14 +851,14 @@ final class NativeMapView {
}
public void setApiBaseUrl(String baseUrl) {
- if (isDestroyedOn("setApiBaseUrl")) {
+ if (checkState("setApiBaseUrl")) {
return;
}
fileSource.setApiBaseUrl(baseUrl);
}
public Light getLight() {
- if (isDestroyedOn("getLight")) {
+ if (checkState("getLight")) {
return null;
}
return nativeGetLight();
@@ -878,7 +892,7 @@ final class NativeMapView {
}
protected void onSnapshotReady(Bitmap mapContent) {
- if (isDestroyedOn("OnSnapshotReady")) {
+ if (checkState("OnSnapshotReady")) {
return;
}
@@ -1077,14 +1091,14 @@ final class NativeMapView {
private native boolean nativeGetPrefetchesTiles();
int getWidth() {
- if (isDestroyedOn("")) {
+ if (checkState("")) {
return 0;
}
return viewCallback.getWidth();
}
int getHeight() {
- if (isDestroyedOn("")) {
+ if (checkState("")) {
return 0;
}
return viewCallback.getHeight();
@@ -1109,7 +1123,7 @@ final class NativeMapView {
//
void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) {
- if (isDestroyedOn("addSnapshotCallback")) {
+ if (checkState("addSnapshotCallback")) {
return;
}
snapshotReadyCallback = callback;
@@ -1184,7 +1198,7 @@ final class NativeMapView {
@Override
protected void onPostExecute(List<Image> images) {
super.onPostExecute(images);
- if (nativeMapView != null && !nativeMapView.isDestroyedOn("nativeAddImages")) {
+ if (nativeMapView != null && !nativeMapView.checkState("nativeAddImages")) {
nativeMapView.nativeAddImages(images.toArray(new Image[images.size()]));
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index f35355533d..d5166c17b0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -43,14 +43,16 @@ public class Projection {
/**
* Returns the spherical Mercator projected meters for a LatLng.
*/
- public ProjectedMeters getProjectedMetersForLatLng(LatLng latLng) {
+ @NonNull
+ public ProjectedMeters getProjectedMetersForLatLng(@NonNull LatLng latLng) {
return nativeMapView.projectedMetersForLatLng(latLng);
}
/**
* Returns the LatLng for a spherical Mercator projected meters.
*/
- public LatLng getLatLngForProjectedMeters(ProjectedMeters projectedMeters) {
+ @NonNull
+ public LatLng getLatLngForProjectedMeters(@NonNull ProjectedMeters projectedMeters) {
return nativeMapView.latLngForProjectedMeters(projectedMeters);
}
@@ -77,7 +79,8 @@ public class Projection {
* @return The LatLng corresponding to the point on the screen, or null if the ray through
* the given screen point does not intersect the ground plane.
*/
- public LatLng fromScreenLocation(PointF point) {
+ @NonNull
+ public LatLng fromScreenLocation(@NonNull PointF point) {
return nativeMapView.latLngForPixel(point);
}
@@ -87,6 +90,7 @@ public class Projection {
*
* @return The projection of the viewing frustum in its current state.
*/
+ @NonNull
public VisibleRegion getVisibleRegion() {
float left = 0;
float right = nativeMapView.getWidth();
@@ -151,7 +155,8 @@ public class Projection {
* @param location A LatLng on the map to convert to a screen location.
* @return A Point representing the screen location in screen pixels.
*/
- public PointF toScreenLocation(LatLng location) {
+ @NonNull
+ public PointF toScreenLocation(@NonNull LatLng location) {
return nativeMapView.pixelForLatLng(location);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
index 8aa4c7fd09..307b33b0c7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
@@ -31,6 +31,7 @@ import java.util.List;
public class SupportMapFragment extends Fragment implements OnMapReadyCallback {
private final List<OnMapReadyCallback> mapReadyCallbackList = new ArrayList<>();
+ private MapFragment.OnMapViewReadyCallback mapViewReadyCallback;
private MapboxMap mapboxMap;
private MapView map;
@@ -56,6 +57,19 @@ public class SupportMapFragment extends Fragment implements OnMapReadyCallback {
}
/**
+ * Called when the context attaches to this fragment.
+ *
+ * @param context the context attaching
+ */
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof MapFragment.OnMapViewReadyCallback) {
+ mapViewReadyCallback = (MapFragment.OnMapViewReadyCallback) context;
+ }
+ }
+
+ /**
* Creates the fragment view hierarchy.
*
* @param inflater Inflater used to inflate content.
@@ -82,6 +96,11 @@ public class SupportMapFragment extends Fragment implements OnMapReadyCallback {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
map.getMapAsync(this);
+
+ // notify listeners about MapView creation
+ if (mapViewReadyCallback != null) {
+ mapViewReadyCallback.onMapViewReady(map);
+ }
}
@Override
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 c1daebbe52..100787fbf0 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
@@ -332,7 +332,7 @@ public final class UiSettings {
*
* @param compass the drawable to show as image compass
*/
- public void setCompassImage(Drawable compass) {
+ public void setCompassImage(@NonNull Drawable compass) {
compassView.setCompassImage(compass);
}
@@ -409,6 +409,7 @@ public final class UiSettings {
*
* @return the drawable used as compass image
*/
+ @NonNull
public Drawable getCompassImage() {
return compassView.getCompassImage();
}
@@ -544,7 +545,7 @@ public final class UiSettings {
*
* @param attributionDialogManager the manager class used for showing attribution
*/
- public void setAttributionDialogManager(AttributionDialogManager attributionDialogManager) {
+ public void setAttributionDialogManager(@NonNull AttributionDialogManager attributionDialogManager) {
this.attributionDialogManager = attributionDialogManager;
}
@@ -553,6 +554,7 @@ public final class UiSettings {
*
* @return the active manager class used for showing attribution
*/
+ @NonNull
public AttributionDialogManager getAttributionDialogManager() {
return attributionDialogManager;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
index 0895096f6e..641c283798 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -16,7 +16,6 @@ import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.attribution.AttributionLayout;
import com.mapbox.mapboxsdk.attribution.AttributionMeasure;
@@ -25,7 +24,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.storage.FileSource;
-
+import com.mapbox.mapboxsdk.utils.ThreadUtils;
import timber.log.Timber;
/**
@@ -86,6 +85,7 @@ public class MapSnapshotter {
private int width;
private int height;
private String styleUrl = Style.MAPBOX_STREETS;
+ private String styleJson;
private LatLngBounds region;
private CameraPosition cameraPosition;
private boolean showLogo = true;
@@ -112,6 +112,15 @@ public class MapSnapshotter {
}
/**
+ * @param styleJson The style json to use
+ * @return the mutated {@link Options}
+ */
+ public Options withStyleJson(String styleJson) {
+ this.styleJson = styleJson;
+ return this;
+ }
+
+ /**
* @param region the region to show in the snapshot.
* This is applied after the camera position
* @return the mutated {@link Options}
@@ -203,12 +212,13 @@ public class MapSnapshotter {
* @param options the options to use for the snapshot
*/
public MapSnapshotter(@NonNull Context context, @NonNull Options options) {
+ checkThread();
this.context = context.getApplicationContext();
FileSource fileSource = FileSource.getInstance(context);
String programCacheDir = context.getCacheDir().getAbsolutePath();
nativeInitialize(this, fileSource, options.pixelRatio, options.width,
- options.height, options.styleUrl, options.region, options.cameraPosition,
+ options.height, options.styleUrl, options.styleJson, options.region, options.cameraPosition,
options.showLogo, programCacheDir);
}
@@ -233,7 +243,7 @@ public class MapSnapshotter {
if (this.callback != null) {
throw new IllegalStateException("Snapshotter was already started");
}
-
+ checkThread();
this.callback = callback;
this.errorHandler = errorHandler;
nativeStart();
@@ -274,6 +284,7 @@ public class MapSnapshotter {
* the object was created on.
*/
public void cancel() {
+ checkThread();
reset();
nativeCancel();
}
@@ -455,6 +466,10 @@ public class MapSnapshotter {
}
}
+ private void checkThread() {
+ ThreadUtils.checkThread("MapSnapshotter");
+ }
+
protected void reset() {
callback = null;
errorHandler = null;
@@ -462,7 +477,7 @@ public class MapSnapshotter {
protected native void nativeInitialize(MapSnapshotter mapSnapshotter,
FileSource fileSource, float pixelRatio,
- int width, int height, String styleUrl,
+ int width, int height, String styleUrl, String styleJson,
LatLngBounds region, CameraPosition position,
boolean showLogo, String programCacheDir);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
index f0cb8d973a..929e4b4279 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -6,6 +6,8 @@ import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Environment;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import timber.log.Timber;
@@ -43,6 +45,7 @@ public class FileSource {
* @param context the context to derive the cache path from
* @return the single instance of FileSource
*/
+ @UiThread
public static synchronized FileSource getInstance(Context context) {
if (INSTANCE == null) {
String cachePath = getCachePath(context);
@@ -122,6 +125,8 @@ public class FileSource {
initialize(Mapbox.getAccessToken(), cachePath, assetManager);
}
+ public native boolean isActivated();
+
public native void activate();
public native void deactivate();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
index 44ad5e83ed..eb9150ecbc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -4,9 +4,10 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.Size;
-
+import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
import com.google.gson.JsonPrimitive;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.PropertyValue;
@@ -178,6 +179,8 @@ public class Expression {
public static Expression literal(@NonNull Object object) {
if (object.getClass().isArray()) {
return literal(ExpressionArray.toObjectArray(object));
+ } else if (object instanceof Expression) {
+ throw new RuntimeException("Can't convert an expression to a literal");
}
return new ExpressionLiteral(object);
}
@@ -210,7 +213,8 @@ public class Expression {
* @return the color expression
*/
public static Expression color(@ColorInt int color) {
- return toColor(literal(PropertyFactory.colorToRgbaString(color)));
+ int[] rgba = PropertyFactory.colorToRgbaArray(color);
+ return rgba(rgba[0], rgba[1], rgba[2], rgba[3]);
}
/**
@@ -423,7 +427,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a>
*/
public static Expression eq(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return eq(literal(compareOne), literal(compareTwo));
+ return eq(compareOne, literal(compareTwo));
}
/**
@@ -446,7 +450,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-==">Style specification</a>
*/
public static Expression eq(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return eq(literal(compareOne), literal(compareTwo));
+ return eq(compareOne, literal(compareTwo));
}
/**
@@ -493,7 +497,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a>
*/
public static Expression neq(Expression compareOne, boolean compareTwo) {
- return new Expression("!=", literal(compareOne), literal(compareTwo));
+ return new Expression("!=", compareOne, literal(compareTwo));
}
/**
@@ -516,7 +520,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a>
*/
public static Expression neq(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return new Expression("!=", literal(compareOne), literal(compareTwo));
+ return new Expression("!=", compareOne, literal(compareTwo));
}
/**
@@ -539,7 +543,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-!=">Style specification</a>
*/
public static Expression neq(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return new Expression("!=", literal(compareOne), literal(compareTwo));
+ return new Expression("!=", compareOne, literal(compareTwo));
}
/**
@@ -586,7 +590,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E">Style specification</a>
*/
public static Expression gt(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return new Expression(">", literal(compareOne), literal(compareTwo));
+ return new Expression(">", compareOne, literal(compareTwo));
}
/**
@@ -609,7 +613,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E">Style specification</a>
*/
public static Expression gt(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return new Expression(">", literal(compareOne), literal(compareTwo));
+ return new Expression(">", compareOne, literal(compareTwo));
}
/**
@@ -656,7 +660,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C">Style specification</a>
*/
public static Expression lt(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return new Expression("<", literal(compareOne), literal(compareTwo));
+ return new Expression("<", compareOne, literal(compareTwo));
}
/**
@@ -679,7 +683,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C">Style specification</a>
*/
public static Expression lt(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return new Expression("<", literal(compareOne), literal(compareTwo));
+ return new Expression("<", compareOne, literal(compareTwo));
}
/**
@@ -726,7 +730,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E%3D">Style specification</a>
*/
public static Expression gte(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return new Expression(">=", literal(compareOne), literal(compareTwo));
+ return new Expression(">=", compareOne, literal(compareTwo));
}
/**
@@ -749,7 +753,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3E%3D">Style specification</a>
*/
public static Expression gte(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return new Expression(">=", literal(compareOne), literal(compareTwo));
+ return new Expression(">=", compareOne, literal(compareTwo));
}
/**
@@ -796,7 +800,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C%3D">Style specification</a>
*/
public static Expression lte(@NonNull Expression compareOne, @NonNull Number compareTwo) {
- return new Expression("<=", literal(compareOne), literal(compareTwo));
+ return new Expression("<=", compareOne, literal(compareTwo));
}
/**
@@ -819,7 +823,7 @@ public class Expression {
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-%3C%3D">Style specification</a>
*/
public static Expression lte(@NonNull Expression compareOne, @NonNull String compareTwo) {
- return new Expression("<=", literal(compareOne), literal(compareTwo));
+ return new Expression("<=", compareOne, literal(compareTwo));
}
/**
@@ -2426,6 +2430,7 @@ public class Expression {
* );
* }
* </pre>
+ *
* @param number number to get value from
* @return expression
* @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-abs">Style specification</a>
@@ -3452,6 +3457,10 @@ public class Expression {
/**
* Returns a string representation of the object that matches the definition set in the style specification.
+ * <p>
+ * If this expression contains a coma (,) delimited literal, like 'rgba(r, g, b, a)`,
+ * it will be enclosed with double quotes (").
+ * </p>
*
* @return a string representation of the object.
*/
@@ -3463,7 +3472,17 @@ public class Expression {
for (Object argument : arguments) {
builder.append(", ");
if (argument instanceof ExpressionLiteral) {
- builder.append(((ExpressionLiteral) argument).toValue());
+ Object literalValue = ((ExpressionLiteral) argument).toValue();
+
+ // special case for handling unusual input like 'rgba(r, g, b, a)'
+ if (literalValue instanceof String) {
+ if (((String) literalValue).contains(",")) {
+ builder.append("\"").append(literalValue).append("\"");
+ continue;
+ }
+ }
+
+ builder.append(literalValue);
} else {
builder.append(argument.toString());
}
@@ -3474,6 +3493,26 @@ public class Expression {
}
/**
+ * Returns a DSL equivalent of a raw expression.
+ * <p>
+ * If your raw expression contains a coma (,) delimited literal it has to be enclosed with double quotes ("),
+ * for example
+ * </p>
+ * <pre>
+ * {@code
+ * ["to-color", "rgba(255, 0, 0, 255)"]
+ * }
+ * </pre>
+ *
+ * @param rawExpression the raw expression
+ * @return the resulting expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/">Style specification</a>
+ */
+ public static Expression raw(@NonNull String rawExpression) {
+ return Converter.convert(rawExpression);
+ }
+
+ /**
* Indicates whether some other object is "equal to" this one.
*
* @param o the other object
@@ -3527,6 +3566,11 @@ public class Expression {
* @param object the object to be treated as literal
*/
public ExpressionLiteral(@NonNull Object object) {
+ if (object instanceof String) {
+ object = unwrapStringLiteral((String) object);
+ } else if (object instanceof Number) {
+ object = ((Number) object).floatValue();
+ }
this.literal = object;
}
@@ -3539,6 +3583,12 @@ public class Expression {
return literal;
}
+ @NonNull
+ @Override
+ public Object[] toArray() {
+ return new Object[] {"literal", literal};
+ }
+
/**
* Returns a string representation of the expression literal.
*
@@ -3583,6 +3633,15 @@ public class Expression {
result = 31 * result + (literal != null ? literal.hashCode() : 0);
return result;
}
+
+ private String unwrapStringLiteral(String value) {
+ if (value.length() > 1 &&
+ value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"') {
+ return value.substring(1, value.length() - 1);
+ } else {
+ return value;
+ }
+ }
}
/**
@@ -3652,10 +3711,12 @@ public class Expression {
}
/**
- * Converts a JsonArray to an expression.
+ * Converts a JsonArray or a raw expression to a Java expression.
*/
public final static class Converter {
+ private static final Gson gson = new Gson();
+
/**
* Converts a JsonArray to an expression
*
@@ -3677,6 +3738,8 @@ public class Expression {
arguments.add(convert((JsonArray) jsonElement));
} else if (jsonElement instanceof JsonPrimitive) {
arguments.add(convert((JsonPrimitive) jsonElement));
+ } else if (jsonElement instanceof JsonNull) {
+ arguments.add(new Expression.ExpressionLiteral(""));
} else {
throw new RuntimeException("Unsupported expression conversion for " + jsonElement.getClass());
}
@@ -3701,6 +3764,17 @@ public class Expression {
throw new RuntimeException("Unsupported literal expression conversion for " + jsonPrimitive.getClass());
}
}
+
+ /**
+ * Converts a raw expression to a DSL equivalent.
+ *
+ * @param rawExpression the raw expression to convert
+ * @return the resulting expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/">Style specification</a>
+ */
+ public static Expression convert(@NonNull String rawExpression) {
+ return convert(gson.fromJson(rawExpression, JsonArray.class));
+ }
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
index 60c2aa907b..0a0c3f1e43 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
@@ -36,6 +36,7 @@ public class BackgroundLayer extends Layer {
* @param layerId the id of the layer
*/
public BackgroundLayer(String layerId) {
+ super();
initialize(layerId);
}
@@ -61,6 +62,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getBackgroundColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("background-color", nativeGetBackgroundColor());
}
@@ -72,6 +74,7 @@ public class BackgroundLayer extends Layer {
*/
@ColorInt
public int getBackgroundColorAsInt() {
+ checkThread();
PropertyValue<String> value = getBackgroundColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -86,6 +89,7 @@ public class BackgroundLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getBackgroundColorTransition() {
+ checkThread();
return nativeGetBackgroundColorTransition();
}
@@ -95,6 +99,7 @@ public class BackgroundLayer extends Layer {
* @param options transition options for String
*/
public void setBackgroundColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetBackgroundColorTransition(options.getDuration(), options.getDelay());
}
@@ -105,6 +110,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getBackgroundPattern() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("background-pattern", nativeGetBackgroundPattern());
}
@@ -114,6 +120,7 @@ public class BackgroundLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getBackgroundPatternTransition() {
+ checkThread();
return nativeGetBackgroundPatternTransition();
}
@@ -123,6 +130,7 @@ public class BackgroundLayer extends Layer {
* @param options transition options for String
*/
public void setBackgroundPatternTransition(TransitionOptions options) {
+ checkThread();
nativeSetBackgroundPatternTransition(options.getDuration(), options.getDelay());
}
@@ -133,6 +141,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getBackgroundOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("background-opacity", nativeGetBackgroundOpacity());
}
@@ -142,6 +151,7 @@ public class BackgroundLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getBackgroundOpacityTransition() {
+ checkThread();
return nativeGetBackgroundOpacityTransition();
}
@@ -151,6 +161,7 @@ public class BackgroundLayer extends Layer {
* @param options transition options for Float
*/
public void setBackgroundOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetBackgroundOpacityTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
index 94929398d5..c85cfba0a5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
@@ -37,6 +37,7 @@ public class CircleLayer extends Layer {
* @param sourceId the id of the source
*/
public CircleLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class CircleLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class CircleLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class CircleLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class CircleLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleRadius() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("circle-radius", nativeGetCircleRadius());
}
@@ -135,6 +141,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getCircleRadiusTransition() {
+ checkThread();
return nativeGetCircleRadiusTransition();
}
@@ -144,6 +151,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float
*/
public void setCircleRadiusTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleRadiusTransition(options.getDuration(), options.getDelay());
}
@@ -154,6 +162,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("circle-color", nativeGetCircleColor());
}
@@ -165,6 +174,7 @@ public class CircleLayer extends Layer {
*/
@ColorInt
public int getCircleColorAsInt() {
+ checkThread();
PropertyValue<String> value = getCircleColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -179,6 +189,7 @@ public class CircleLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getCircleColorTransition() {
+ checkThread();
return nativeGetCircleColorTransition();
}
@@ -188,6 +199,7 @@ public class CircleLayer extends Layer {
* @param options transition options for String
*/
public void setCircleColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleColorTransition(options.getDuration(), options.getDelay());
}
@@ -198,6 +210,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleBlur() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("circle-blur", nativeGetCircleBlur());
}
@@ -207,6 +220,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getCircleBlurTransition() {
+ checkThread();
return nativeGetCircleBlurTransition();
}
@@ -216,6 +230,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float
*/
public void setCircleBlurTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleBlurTransition(options.getDuration(), options.getDelay());
}
@@ -226,6 +241,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("circle-opacity", nativeGetCircleOpacity());
}
@@ -235,6 +251,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getCircleOpacityTransition() {
+ checkThread();
return nativeGetCircleOpacityTransition();
}
@@ -244,6 +261,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float
*/
public void setCircleOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -254,6 +272,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getCircleTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("circle-translate", nativeGetCircleTranslate());
}
@@ -263,6 +282,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getCircleTranslateTransition() {
+ checkThread();
return nativeGetCircleTranslateTransition();
}
@@ -272,6 +292,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float[]
*/
public void setCircleTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -282,6 +303,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("circle-translate-anchor", nativeGetCircleTranslateAnchor());
}
@@ -292,6 +314,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCirclePitchScale() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("circle-pitch-scale", nativeGetCirclePitchScale());
}
@@ -302,6 +325,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCirclePitchAlignment() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("circle-pitch-alignment", nativeGetCirclePitchAlignment());
}
@@ -312,6 +336,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleStrokeWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("circle-stroke-width", nativeGetCircleStrokeWidth());
}
@@ -321,6 +346,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getCircleStrokeWidthTransition() {
+ checkThread();
return nativeGetCircleStrokeWidthTransition();
}
@@ -330,6 +356,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float
*/
public void setCircleStrokeWidthTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleStrokeWidthTransition(options.getDuration(), options.getDelay());
}
@@ -340,6 +367,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleStrokeColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("circle-stroke-color", nativeGetCircleStrokeColor());
}
@@ -351,6 +379,7 @@ public class CircleLayer extends Layer {
*/
@ColorInt
public int getCircleStrokeColorAsInt() {
+ checkThread();
PropertyValue<String> value = getCircleStrokeColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -365,6 +394,7 @@ public class CircleLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getCircleStrokeColorTransition() {
+ checkThread();
return nativeGetCircleStrokeColorTransition();
}
@@ -374,6 +404,7 @@ public class CircleLayer extends Layer {
* @param options transition options for String
*/
public void setCircleStrokeColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleStrokeColorTransition(options.getDuration(), options.getDelay());
}
@@ -384,6 +415,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleStrokeOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("circle-stroke-opacity", nativeGetCircleStrokeOpacity());
}
@@ -393,6 +425,7 @@ public class CircleLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getCircleStrokeOpacityTransition() {
+ checkThread();
return nativeGetCircleStrokeOpacityTransition();
}
@@ -402,6 +435,7 @@ public class CircleLayer extends Layer {
* @param options transition options for Float
*/
public void setCircleStrokeOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetCircleStrokeOpacityTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
index 29e2b49d76..fdfc8c51a9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
@@ -37,6 +37,7 @@ public class FillExtrusionLayer extends Layer {
* @param sourceId the id of the source
*/
public FillExtrusionLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class FillExtrusionLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class FillExtrusionLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class FillExtrusionLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class FillExtrusionLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getFillExtrusionOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("fill-extrusion-opacity", nativeGetFillExtrusionOpacity());
}
@@ -135,6 +141,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getFillExtrusionOpacityTransition() {
+ checkThread();
return nativeGetFillExtrusionOpacityTransition();
}
@@ -144,6 +151,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for Float
*/
public void setFillExtrusionOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -154,6 +162,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillExtrusionColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-extrusion-color", nativeGetFillExtrusionColor());
}
@@ -165,6 +174,7 @@ public class FillExtrusionLayer extends Layer {
*/
@ColorInt
public int getFillExtrusionColorAsInt() {
+ checkThread();
PropertyValue<String> value = getFillExtrusionColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -179,6 +189,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getFillExtrusionColorTransition() {
+ checkThread();
return nativeGetFillExtrusionColorTransition();
}
@@ -188,6 +199,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for String
*/
public void setFillExtrusionColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionColorTransition(options.getDuration(), options.getDelay());
}
@@ -198,6 +210,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getFillExtrusionTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("fill-extrusion-translate", nativeGetFillExtrusionTranslate());
}
@@ -207,6 +220,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getFillExtrusionTranslateTransition() {
+ checkThread();
return nativeGetFillExtrusionTranslateTransition();
}
@@ -216,6 +230,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for Float[]
*/
public void setFillExtrusionTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -226,6 +241,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillExtrusionTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-extrusion-translate-anchor", nativeGetFillExtrusionTranslateAnchor());
}
@@ -236,6 +252,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillExtrusionPattern() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-extrusion-pattern", nativeGetFillExtrusionPattern());
}
@@ -245,6 +262,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getFillExtrusionPatternTransition() {
+ checkThread();
return nativeGetFillExtrusionPatternTransition();
}
@@ -254,6 +272,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for String
*/
public void setFillExtrusionPatternTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionPatternTransition(options.getDuration(), options.getDelay());
}
@@ -264,6 +283,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getFillExtrusionHeight() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("fill-extrusion-height", nativeGetFillExtrusionHeight());
}
@@ -273,6 +293,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getFillExtrusionHeightTransition() {
+ checkThread();
return nativeGetFillExtrusionHeightTransition();
}
@@ -282,6 +303,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for Float
*/
public void setFillExtrusionHeightTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionHeightTransition(options.getDuration(), options.getDelay());
}
@@ -292,6 +314,7 @@ public class FillExtrusionLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getFillExtrusionBase() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("fill-extrusion-base", nativeGetFillExtrusionBase());
}
@@ -301,6 +324,7 @@ public class FillExtrusionLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getFillExtrusionBaseTransition() {
+ checkThread();
return nativeGetFillExtrusionBaseTransition();
}
@@ -310,6 +334,7 @@ public class FillExtrusionLayer extends Layer {
* @param options transition options for Float
*/
public void setFillExtrusionBaseTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillExtrusionBaseTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
index ed780811c0..b51c49e517 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
@@ -37,6 +37,7 @@ public class FillLayer extends Layer {
* @param sourceId the id of the source
*/
public FillLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class FillLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class FillLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class FillLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class FillLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getFillAntialias() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("fill-antialias", nativeGetFillAntialias());
}
@@ -136,6 +142,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getFillOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("fill-opacity", nativeGetFillOpacity());
}
@@ -145,6 +152,7 @@ public class FillLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getFillOpacityTransition() {
+ checkThread();
return nativeGetFillOpacityTransition();
}
@@ -154,6 +162,7 @@ public class FillLayer extends Layer {
* @param options transition options for Float
*/
public void setFillOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -164,6 +173,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-color", nativeGetFillColor());
}
@@ -175,6 +185,7 @@ public class FillLayer extends Layer {
*/
@ColorInt
public int getFillColorAsInt() {
+ checkThread();
PropertyValue<String> value = getFillColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -189,6 +200,7 @@ public class FillLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getFillColorTransition() {
+ checkThread();
return nativeGetFillColorTransition();
}
@@ -198,6 +210,7 @@ public class FillLayer extends Layer {
* @param options transition options for String
*/
public void setFillColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillColorTransition(options.getDuration(), options.getDelay());
}
@@ -208,6 +221,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillOutlineColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-outline-color", nativeGetFillOutlineColor());
}
@@ -219,6 +233,7 @@ public class FillLayer extends Layer {
*/
@ColorInt
public int getFillOutlineColorAsInt() {
+ checkThread();
PropertyValue<String> value = getFillOutlineColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -233,6 +248,7 @@ public class FillLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getFillOutlineColorTransition() {
+ checkThread();
return nativeGetFillOutlineColorTransition();
}
@@ -242,6 +258,7 @@ public class FillLayer extends Layer {
* @param options transition options for String
*/
public void setFillOutlineColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillOutlineColorTransition(options.getDuration(), options.getDelay());
}
@@ -252,6 +269,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getFillTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("fill-translate", nativeGetFillTranslate());
}
@@ -261,6 +279,7 @@ public class FillLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getFillTranslateTransition() {
+ checkThread();
return nativeGetFillTranslateTransition();
}
@@ -270,6 +289,7 @@ public class FillLayer extends Layer {
* @param options transition options for Float[]
*/
public void setFillTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -280,6 +300,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-translate-anchor", nativeGetFillTranslateAnchor());
}
@@ -290,6 +311,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillPattern() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("fill-pattern", nativeGetFillPattern());
}
@@ -299,6 +321,7 @@ public class FillLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getFillPatternTransition() {
+ checkThread();
return nativeGetFillPatternTransition();
}
@@ -308,6 +331,7 @@ public class FillLayer extends Layer {
* @param options transition options for String
*/
public void setFillPatternTransition(TransitionOptions options) {
+ checkThread();
nativeSetFillPatternTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java
index 42b4210710..d28e4bd838 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java
@@ -37,6 +37,7 @@ public class HeatmapLayer extends Layer {
* @param sourceId the id of the source
*/
public HeatmapLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class HeatmapLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class HeatmapLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class HeatmapLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class HeatmapLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class HeatmapLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapRadius() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("heatmap-radius", nativeGetHeatmapRadius());
}
@@ -135,6 +141,7 @@ public class HeatmapLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getHeatmapRadiusTransition() {
+ checkThread();
return nativeGetHeatmapRadiusTransition();
}
@@ -144,6 +151,7 @@ public class HeatmapLayer extends Layer {
* @param options transition options for Float
*/
public void setHeatmapRadiusTransition(TransitionOptions options) {
+ checkThread();
nativeSetHeatmapRadiusTransition(options.getDuration(), options.getDelay());
}
@@ -154,6 +162,7 @@ public class HeatmapLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapWeight() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("heatmap-weight", nativeGetHeatmapWeight());
}
@@ -164,6 +173,7 @@ public class HeatmapLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapIntensity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("heatmap-intensity", nativeGetHeatmapIntensity());
}
@@ -173,6 +183,7 @@ public class HeatmapLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getHeatmapIntensityTransition() {
+ checkThread();
return nativeGetHeatmapIntensityTransition();
}
@@ -182,6 +193,7 @@ public class HeatmapLayer extends Layer {
* @param options transition options for Float
*/
public void setHeatmapIntensityTransition(TransitionOptions options) {
+ checkThread();
nativeSetHeatmapIntensityTransition(options.getDuration(), options.getDelay());
}
@@ -192,6 +204,7 @@ public class HeatmapLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getHeatmapColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("heatmap-color", nativeGetHeatmapColor());
}
@@ -203,6 +216,7 @@ public class HeatmapLayer extends Layer {
*/
@ColorInt
public int getHeatmapColorAsInt() {
+ checkThread();
PropertyValue<String> value = getHeatmapColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -218,6 +232,7 @@ public class HeatmapLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHeatmapOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("heatmap-opacity", nativeGetHeatmapOpacity());
}
@@ -227,6 +242,7 @@ public class HeatmapLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getHeatmapOpacityTransition() {
+ checkThread();
return nativeGetHeatmapOpacityTransition();
}
@@ -236,6 +252,7 @@ public class HeatmapLayer extends Layer {
* @param options transition options for Float
*/
public void setHeatmapOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetHeatmapOpacityTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java
index fb086f424b..75a2607b05 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java
@@ -37,6 +37,7 @@ public class HillshadeLayer extends Layer {
* @param sourceId the id of the source
*/
public HillshadeLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class HillshadeLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -82,6 +84,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHillshadeIlluminationDirection() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("hillshade-illumination-direction", nativeGetHillshadeIlluminationDirection());
}
@@ -92,6 +95,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getHillshadeIlluminationAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("hillshade-illumination-anchor", nativeGetHillshadeIlluminationAnchor());
}
@@ -102,6 +106,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getHillshadeExaggeration() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("hillshade-exaggeration", nativeGetHillshadeExaggeration());
}
@@ -111,6 +116,7 @@ public class HillshadeLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getHillshadeExaggerationTransition() {
+ checkThread();
return nativeGetHillshadeExaggerationTransition();
}
@@ -120,6 +126,7 @@ public class HillshadeLayer extends Layer {
* @param options transition options for Float
*/
public void setHillshadeExaggerationTransition(TransitionOptions options) {
+ checkThread();
nativeSetHillshadeExaggerationTransition(options.getDuration(), options.getDelay());
}
@@ -130,6 +137,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getHillshadeShadowColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("hillshade-shadow-color", nativeGetHillshadeShadowColor());
}
@@ -141,6 +149,7 @@ public class HillshadeLayer extends Layer {
*/
@ColorInt
public int getHillshadeShadowColorAsInt() {
+ checkThread();
PropertyValue<String> value = getHillshadeShadowColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -155,6 +164,7 @@ public class HillshadeLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getHillshadeShadowColorTransition() {
+ checkThread();
return nativeGetHillshadeShadowColorTransition();
}
@@ -164,6 +174,7 @@ public class HillshadeLayer extends Layer {
* @param options transition options for String
*/
public void setHillshadeShadowColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetHillshadeShadowColorTransition(options.getDuration(), options.getDelay());
}
@@ -174,6 +185,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getHillshadeHighlightColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("hillshade-highlight-color", nativeGetHillshadeHighlightColor());
}
@@ -185,6 +197,7 @@ public class HillshadeLayer extends Layer {
*/
@ColorInt
public int getHillshadeHighlightColorAsInt() {
+ checkThread();
PropertyValue<String> value = getHillshadeHighlightColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -199,6 +212,7 @@ public class HillshadeLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getHillshadeHighlightColorTransition() {
+ checkThread();
return nativeGetHillshadeHighlightColorTransition();
}
@@ -208,6 +222,7 @@ public class HillshadeLayer extends Layer {
* @param options transition options for String
*/
public void setHillshadeHighlightColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetHillshadeHighlightColorTransition(options.getDuration(), options.getDelay());
}
@@ -218,6 +233,7 @@ public class HillshadeLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getHillshadeAccentColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("hillshade-accent-color", nativeGetHillshadeAccentColor());
}
@@ -229,6 +245,7 @@ public class HillshadeLayer extends Layer {
*/
@ColorInt
public int getHillshadeAccentColorAsInt() {
+ checkThread();
PropertyValue<String> value = getHillshadeAccentColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -243,6 +260,7 @@ public class HillshadeLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getHillshadeAccentColorTransition() {
+ checkThread();
return nativeGetHillshadeAccentColorTransition();
}
@@ -252,6 +270,7 @@ public class HillshadeLayer extends Layer {
* @param options transition options for String
*/
public void setHillshadeAccentColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetHillshadeAccentColorTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
index 411fbe4435..3edc202c8e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
@@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.NonNull;
-import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.utils.ThreadUtils;
/**
* Base class for the different Layer types
@@ -15,13 +15,23 @@ public abstract class Layer {
private boolean invalidated;
public Layer(long nativePtr) {
+ checkThread();
this.nativePtr = nativePtr;
}
public Layer() {
+ checkThread();
+ }
+
+ /**
+ * Validates if layer interaction is happening on the UI thread
+ */
+ protected void checkThread() {
+ ThreadUtils.checkThread("Layer");
}
public void setProperties(@NonNull PropertyValue<?>... properties) {
+ checkThread();
if (properties.length == 0) {
return;
}
@@ -37,26 +47,32 @@ public abstract class Layer {
}
public String getId() {
+ checkThread();
return nativeGetId();
}
public PropertyValue<String> getVisibility() {
+ checkThread();
return new PaintPropertyValue<>("visibility", (String) nativeGetVisibility());
}
public float getMinZoom() {
+ checkThread();
return nativeGetMinZoom();
}
public float getMaxZoom() {
+ checkThread();
return nativeGetMaxZoom();
}
public void setMinZoom(float zoom) {
+ checkThread();
nativeSetMinZoom(zoom);
}
public void setMaxZoom(float zoom) {
+ checkThread();
nativeSetMaxZoom(zoom);
}
@@ -97,5 +113,4 @@ public abstract class Layer {
}
return value;
}
-
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
index 5e6e6d38e7..b094162c4b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
@@ -37,6 +37,7 @@ public class LineLayer extends Layer {
* @param sourceId the id of the source
*/
public LineLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class LineLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class LineLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class LineLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class LineLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineCap() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("line-cap", nativeGetLineCap());
}
@@ -136,6 +142,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineJoin() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("line-join", nativeGetLineJoin());
}
@@ -146,6 +153,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineMiterLimit() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-miter-limit", nativeGetLineMiterLimit());
}
@@ -156,6 +164,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineRoundLimit() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-round-limit", nativeGetLineRoundLimit());
}
@@ -166,6 +175,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-opacity", nativeGetLineOpacity());
}
@@ -175,6 +185,7 @@ public class LineLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getLineOpacityTransition() {
+ checkThread();
return nativeGetLineOpacityTransition();
}
@@ -184,6 +195,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float
*/
public void setLineOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -194,6 +206,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("line-color", nativeGetLineColor());
}
@@ -205,6 +218,7 @@ public class LineLayer extends Layer {
*/
@ColorInt
public int getLineColorAsInt() {
+ checkThread();
PropertyValue<String> value = getLineColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -219,6 +233,7 @@ public class LineLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getLineColorTransition() {
+ checkThread();
return nativeGetLineColorTransition();
}
@@ -228,6 +243,7 @@ public class LineLayer extends Layer {
* @param options transition options for String
*/
public void setLineColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineColorTransition(options.getDuration(), options.getDelay());
}
@@ -238,6 +254,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getLineTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("line-translate", nativeGetLineTranslate());
}
@@ -247,6 +264,7 @@ public class LineLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getLineTranslateTransition() {
+ checkThread();
return nativeGetLineTranslateTransition();
}
@@ -256,6 +274,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float[]
*/
public void setLineTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -266,6 +285,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("line-translate-anchor", nativeGetLineTranslateAnchor());
}
@@ -276,6 +296,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-width", nativeGetLineWidth());
}
@@ -285,6 +306,7 @@ public class LineLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getLineWidthTransition() {
+ checkThread();
return nativeGetLineWidthTransition();
}
@@ -294,6 +316,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float
*/
public void setLineWidthTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineWidthTransition(options.getDuration(), options.getDelay());
}
@@ -304,6 +327,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineGapWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-gap-width", nativeGetLineGapWidth());
}
@@ -313,6 +337,7 @@ public class LineLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getLineGapWidthTransition() {
+ checkThread();
return nativeGetLineGapWidthTransition();
}
@@ -322,6 +347,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float
*/
public void setLineGapWidthTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineGapWidthTransition(options.getDuration(), options.getDelay());
}
@@ -332,6 +358,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineOffset() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-offset", nativeGetLineOffset());
}
@@ -341,6 +368,7 @@ public class LineLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getLineOffsetTransition() {
+ checkThread();
return nativeGetLineOffsetTransition();
}
@@ -350,6 +378,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float
*/
public void setLineOffsetTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineOffsetTransition(options.getDuration(), options.getDelay());
}
@@ -360,6 +389,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineBlur() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("line-blur", nativeGetLineBlur());
}
@@ -369,6 +399,7 @@ public class LineLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getLineBlurTransition() {
+ checkThread();
return nativeGetLineBlurTransition();
}
@@ -378,6 +409,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float
*/
public void setLineBlurTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineBlurTransition(options.getDuration(), options.getDelay());
}
@@ -388,6 +420,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getLineDasharray() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("line-dasharray", nativeGetLineDasharray());
}
@@ -397,6 +430,7 @@ public class LineLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getLineDasharrayTransition() {
+ checkThread();
return nativeGetLineDasharrayTransition();
}
@@ -406,6 +440,7 @@ public class LineLayer extends Layer {
* @param options transition options for Float[]
*/
public void setLineDasharrayTransition(TransitionOptions options) {
+ checkThread();
nativeSetLineDasharrayTransition(options.getDuration(), options.getDelay());
}
@@ -416,6 +451,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLinePattern() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("line-pattern", nativeGetLinePattern());
}
@@ -425,6 +461,7 @@ public class LineLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getLinePatternTransition() {
+ checkThread();
return nativeGetLinePatternTransition();
}
@@ -434,6 +471,7 @@ public class LineLayer extends Layer {
* @param options transition options for String
*/
public void setLinePatternTransition(TransitionOptions options) {
+ checkThread();
nativeSetLinePatternTransition(options.getDuration(), options.getDelay());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 4289deeda3..57638920be 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -166,7 +166,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -176,7 +176,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -356,7 +356,7 @@ public class PropertyFactory {
}
/**
- * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a Float[] value
* @return property wrapper around Float[]
@@ -366,7 +366,7 @@ public class PropertyFactory {
}
/**
- * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -376,7 +376,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -386,7 +386,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -1156,7 +1156,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -1166,7 +1166,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -1536,7 +1536,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -1546,7 +1546,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -2375,9 +2375,24 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-optional", value);
}
- public static String colorToRgbaString(@ColorInt int value) {
- return String.format(Locale.US,"rgba(%d, %d, %d, %d)",
- (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
+ /**
+ * Converts Android color int to "rbga(r, g, b, a)" String equivalent.
+ *
+ * @param color Android color int
+ * @return String rgba color
+ */
+ public static String colorToRgbaString(@ColorInt int color) {
+ return String.format(Locale.US, "rgba(%d, %d, %d, %d)",
+ (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF);
}
+ /**
+ * Converts Android color int to rgba int array.
+ *
+ * @param color Android color int
+ * @return int rgba array
+ */
+ public static int[] colorToRgbaArray(@ColorInt int color) {
+ return new int[] {(color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF};
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
index 0c7948f62a..218ed36744 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
@@ -37,6 +37,7 @@ public class RasterLayer extends Layer {
* @param sourceId the id of the source
*/
public RasterLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class RasterLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -82,6 +84,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-opacity", nativeGetRasterOpacity());
}
@@ -91,6 +94,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterOpacityTransition() {
+ checkThread();
return nativeGetRasterOpacityTransition();
}
@@ -100,6 +104,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -110,6 +115,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterHueRotate() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-hue-rotate", nativeGetRasterHueRotate());
}
@@ -119,6 +125,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterHueRotateTransition() {
+ checkThread();
return nativeGetRasterHueRotateTransition();
}
@@ -128,6 +135,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterHueRotateTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterHueRotateTransition(options.getDuration(), options.getDelay());
}
@@ -138,6 +146,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterBrightnessMin() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-brightness-min", nativeGetRasterBrightnessMin());
}
@@ -147,6 +156,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterBrightnessMinTransition() {
+ checkThread();
return nativeGetRasterBrightnessMinTransition();
}
@@ -156,6 +166,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterBrightnessMinTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterBrightnessMinTransition(options.getDuration(), options.getDelay());
}
@@ -166,6 +177,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterBrightnessMax() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-brightness-max", nativeGetRasterBrightnessMax());
}
@@ -175,6 +187,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterBrightnessMaxTransition() {
+ checkThread();
return nativeGetRasterBrightnessMaxTransition();
}
@@ -184,6 +197,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterBrightnessMaxTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterBrightnessMaxTransition(options.getDuration(), options.getDelay());
}
@@ -194,6 +208,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterSaturation() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-saturation", nativeGetRasterSaturation());
}
@@ -203,6 +218,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterSaturationTransition() {
+ checkThread();
return nativeGetRasterSaturationTransition();
}
@@ -212,6 +228,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterSaturationTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterSaturationTransition(options.getDuration(), options.getDelay());
}
@@ -222,6 +239,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterContrast() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-contrast", nativeGetRasterContrast());
}
@@ -231,6 +249,7 @@ public class RasterLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getRasterContrastTransition() {
+ checkThread();
return nativeGetRasterContrastTransition();
}
@@ -240,6 +259,7 @@ public class RasterLayer extends Layer {
* @param options transition options for Float
*/
public void setRasterContrastTransition(TransitionOptions options) {
+ checkThread();
nativeSetRasterContrastTransition(options.getDuration(), options.getDelay());
}
@@ -250,6 +270,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterFadeDuration() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("raster-fade-duration", nativeGetRasterFadeDuration());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
index 6a2e131d7d..4aefad3956 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
@@ -37,6 +37,7 @@ public class SymbolLayer extends Layer {
* @param sourceId the id of the source
*/
public SymbolLayer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -48,6 +49,7 @@ public class SymbolLayer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -68,6 +70,7 @@ public class SymbolLayer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -77,6 +80,7 @@ public class SymbolLayer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -98,6 +102,7 @@ public class SymbolLayer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -126,6 +131,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getSymbolPlacement() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("symbol-placement", nativeGetSymbolPlacement());
}
@@ -136,6 +142,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getSymbolSpacing() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("symbol-spacing", nativeGetSymbolSpacing());
}
@@ -146,6 +153,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getSymbolAvoidEdges() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("symbol-avoid-edges", nativeGetSymbolAvoidEdges());
}
@@ -156,6 +164,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconAllowOverlap() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("icon-allow-overlap", nativeGetIconAllowOverlap());
}
@@ -166,6 +175,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconIgnorePlacement() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("icon-ignore-placement", nativeGetIconIgnorePlacement());
}
@@ -176,6 +186,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconOptional() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("icon-optional", nativeGetIconOptional());
}
@@ -186,6 +197,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconRotationAlignment() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-rotation-alignment", nativeGetIconRotationAlignment());
}
@@ -196,6 +208,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconSize() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-size", nativeGetIconSize());
}
@@ -206,6 +219,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconTextFit() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-text-fit", nativeGetIconTextFit());
}
@@ -216,6 +230,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconTextFitPadding() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("icon-text-fit-padding", nativeGetIconTextFitPadding());
}
@@ -226,6 +241,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconImage() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-image", nativeGetIconImage());
}
@@ -236,6 +252,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconRotate() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-rotate", nativeGetIconRotate());
}
@@ -246,6 +263,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconPadding() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-padding", nativeGetIconPadding());
}
@@ -256,6 +274,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconKeepUpright() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("icon-keep-upright", nativeGetIconKeepUpright());
}
@@ -266,6 +285,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconOffset() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("icon-offset", nativeGetIconOffset());
}
@@ -276,6 +296,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-anchor", nativeGetIconAnchor());
}
@@ -286,6 +307,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconPitchAlignment() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-pitch-alignment", nativeGetIconPitchAlignment());
}
@@ -296,6 +318,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextPitchAlignment() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-pitch-alignment", nativeGetTextPitchAlignment());
}
@@ -306,6 +329,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextRotationAlignment() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-rotation-alignment", nativeGetTextRotationAlignment());
}
@@ -316,6 +340,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextField() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-field", nativeGetTextField());
}
@@ -326,6 +351,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String[]> getTextFont() {
+ checkThread();
return (PropertyValue<String[]>) new PropertyValue("text-font", nativeGetTextFont());
}
@@ -336,6 +362,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextSize() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-size", nativeGetTextSize());
}
@@ -346,6 +373,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextMaxWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-max-width", nativeGetTextMaxWidth());
}
@@ -356,6 +384,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextLineHeight() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-line-height", nativeGetTextLineHeight());
}
@@ -366,6 +395,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextLetterSpacing() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-letter-spacing", nativeGetTextLetterSpacing());
}
@@ -376,6 +406,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextJustify() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-justify", nativeGetTextJustify());
}
@@ -386,6 +417,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-anchor", nativeGetTextAnchor());
}
@@ -396,6 +428,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextMaxAngle() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-max-angle", nativeGetTextMaxAngle());
}
@@ -406,6 +439,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextRotate() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-rotate", nativeGetTextRotate());
}
@@ -416,6 +450,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextPadding() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-padding", nativeGetTextPadding());
}
@@ -426,6 +461,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextKeepUpright() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("text-keep-upright", nativeGetTextKeepUpright());
}
@@ -436,6 +472,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextTransform() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-transform", nativeGetTextTransform());
}
@@ -446,6 +483,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getTextOffset() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("text-offset", nativeGetTextOffset());
}
@@ -456,6 +494,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextAllowOverlap() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("text-allow-overlap", nativeGetTextAllowOverlap());
}
@@ -466,6 +505,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextIgnorePlacement() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("text-ignore-placement", nativeGetTextIgnorePlacement());
}
@@ -476,6 +516,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextOptional() {
+ checkThread();
return (PropertyValue<Boolean>) new PropertyValue("text-optional", nativeGetTextOptional());
}
@@ -486,6 +527,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-opacity", nativeGetIconOpacity());
}
@@ -495,6 +537,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getIconOpacityTransition() {
+ checkThread();
return nativeGetIconOpacityTransition();
}
@@ -504,6 +547,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setIconOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -514,6 +558,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-color", nativeGetIconColor());
}
@@ -525,6 +570,7 @@ public class SymbolLayer extends Layer {
*/
@ColorInt
public int getIconColorAsInt() {
+ checkThread();
PropertyValue<String> value = getIconColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -539,6 +585,7 @@ public class SymbolLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getIconColorTransition() {
+ checkThread();
return nativeGetIconColorTransition();
}
@@ -548,6 +595,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for String
*/
public void setIconColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconColorTransition(options.getDuration(), options.getDelay());
}
@@ -558,6 +606,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconHaloColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-halo-color", nativeGetIconHaloColor());
}
@@ -569,6 +618,7 @@ public class SymbolLayer extends Layer {
*/
@ColorInt
public int getIconHaloColorAsInt() {
+ checkThread();
PropertyValue<String> value = getIconHaloColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -583,6 +633,7 @@ public class SymbolLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getIconHaloColorTransition() {
+ checkThread();
return nativeGetIconHaloColorTransition();
}
@@ -592,6 +643,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for String
*/
public void setIconHaloColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconHaloColorTransition(options.getDuration(), options.getDelay());
}
@@ -602,6 +654,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconHaloWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-halo-width", nativeGetIconHaloWidth());
}
@@ -611,6 +664,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getIconHaloWidthTransition() {
+ checkThread();
return nativeGetIconHaloWidthTransition();
}
@@ -620,6 +674,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setIconHaloWidthTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconHaloWidthTransition(options.getDuration(), options.getDelay());
}
@@ -630,6 +685,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconHaloBlur() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("icon-halo-blur", nativeGetIconHaloBlur());
}
@@ -639,6 +695,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getIconHaloBlurTransition() {
+ checkThread();
return nativeGetIconHaloBlurTransition();
}
@@ -648,6 +705,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setIconHaloBlurTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconHaloBlurTransition(options.getDuration(), options.getDelay());
}
@@ -658,6 +716,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("icon-translate", nativeGetIconTranslate());
}
@@ -667,6 +726,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getIconTranslateTransition() {
+ checkThread();
return nativeGetIconTranslateTransition();
}
@@ -676,6 +736,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float[]
*/
public void setIconTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetIconTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -686,6 +747,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("icon-translate-anchor", nativeGetIconTranslateAnchor());
}
@@ -696,6 +758,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextOpacity() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-opacity", nativeGetTextOpacity());
}
@@ -705,6 +768,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getTextOpacityTransition() {
+ checkThread();
return nativeGetTextOpacityTransition();
}
@@ -714,6 +778,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setTextOpacityTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextOpacityTransition(options.getDuration(), options.getDelay());
}
@@ -724,6 +789,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-color", nativeGetTextColor());
}
@@ -735,6 +801,7 @@ public class SymbolLayer extends Layer {
*/
@ColorInt
public int getTextColorAsInt() {
+ checkThread();
PropertyValue<String> value = getTextColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -749,6 +816,7 @@ public class SymbolLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getTextColorTransition() {
+ checkThread();
return nativeGetTextColorTransition();
}
@@ -758,6 +826,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for String
*/
public void setTextColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextColorTransition(options.getDuration(), options.getDelay());
}
@@ -768,6 +837,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextHaloColor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-halo-color", nativeGetTextHaloColor());
}
@@ -779,6 +849,7 @@ public class SymbolLayer extends Layer {
*/
@ColorInt
public int getTextHaloColorAsInt() {
+ checkThread();
PropertyValue<String> value = getTextHaloColor();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -793,6 +864,7 @@ public class SymbolLayer extends Layer {
* @return transition options for String
*/
public TransitionOptions getTextHaloColorTransition() {
+ checkThread();
return nativeGetTextHaloColorTransition();
}
@@ -802,6 +874,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for String
*/
public void setTextHaloColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextHaloColorTransition(options.getDuration(), options.getDelay());
}
@@ -812,6 +885,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextHaloWidth() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-halo-width", nativeGetTextHaloWidth());
}
@@ -821,6 +895,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getTextHaloWidthTransition() {
+ checkThread();
return nativeGetTextHaloWidthTransition();
}
@@ -830,6 +905,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setTextHaloWidthTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextHaloWidthTransition(options.getDuration(), options.getDelay());
}
@@ -840,6 +916,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextHaloBlur() {
+ checkThread();
return (PropertyValue<Float>) new PropertyValue("text-halo-blur", nativeGetTextHaloBlur());
}
@@ -849,6 +926,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float
*/
public TransitionOptions getTextHaloBlurTransition() {
+ checkThread();
return nativeGetTextHaloBlurTransition();
}
@@ -858,6 +936,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float
*/
public void setTextHaloBlurTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextHaloBlurTransition(options.getDuration(), options.getDelay());
}
@@ -868,6 +947,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getTextTranslate() {
+ checkThread();
return (PropertyValue<Float[]>) new PropertyValue("text-translate", nativeGetTextTranslate());
}
@@ -877,6 +957,7 @@ public class SymbolLayer extends Layer {
* @return transition options for Float[]
*/
public TransitionOptions getTextTranslateTransition() {
+ checkThread();
return nativeGetTextTranslateTransition();
}
@@ -886,6 +967,7 @@ public class SymbolLayer extends Layer {
* @param options transition options for Float[]
*/
public void setTextTranslateTransition(TransitionOptions options) {
+ checkThread();
nativeSetTextTranslateTransition(options.getDuration(), options.getDelay());
}
@@ -896,6 +978,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextTranslateAnchor() {
+ checkThread();
return (PropertyValue<String>) new PropertyValue("text-translate-anchor", nativeGetTextTranslateAnchor());
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs
index 851a85f3d6..21b0a1d59e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs
@@ -42,6 +42,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @param layerId the id of the layer
*/
public <%- camelize(type) %>Layer(String layerId) {
+ super();
initialize(layerId);
}
@@ -55,6 +56,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @param sourceId the id of the source
*/
public <%- camelize(type) %>Layer(String layerId, String sourceId) {
+ super();
initialize(layerId, sourceId);
}
@@ -66,6 +68,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @param sourceLayer the source layer to set
*/
public void setSourceLayer(String sourceLayer) {
+ checkThread();
nativeSetSourceLayer(sourceLayer);
}
@@ -88,6 +91,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @return sourceLayer the source layer to get
*/
public String getSourceLayer() {
+ checkThread();
return nativeGetSourceLayer();
}
@@ -97,6 +101,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @param filter the expression filter to set
*/
public void setFilter(Expression filter) {
+ checkThread();
nativeSetFilter(filter.toArray());
}
@@ -118,6 +123,7 @@ public class <%- camelize(type) %>Layer extends Layer {
*/
@Nullable
public Expression getFilter() {
+ checkThread();
Expression expression = null;
JsonArray array = (JsonArray) nativeGetFilter();
if (array != null) {
@@ -148,6 +154,7 @@ public class <%- camelize(type) %>Layer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() {
+ checkThread();
return (PropertyValue<<%- propertyType(property) %>>) new PropertyValue("<%- property.name %>", nativeGet<%- camelize(property.name) %>());
}
<% if (property.type == 'color') { -%>
@@ -160,6 +167,7 @@ public class <%- camelize(type) %>Layer extends Layer {
*/
@ColorInt
public int get<%- camelize(property.name) %>AsInt() {
+ checkThread();
PropertyValue<<%- propertyType(property) %>> value = get<%- camelize(property.name) %>();
if (value.isValue()) {
return rgbaToColor(value.getValue());
@@ -176,6 +184,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @return transition options for <%- propertyType(property) %>
*/
public TransitionOptions get<%- camelize(property.name) %>Transition() {
+ checkThread();
return nativeGet<%- camelize(property.name) %>Transition();
}
@@ -185,6 +194,7 @@ public class <%- camelize(type) %>Layer extends Layer {
* @param options transition options for <%- propertyType(property) %>
*/
public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
+ checkThread();
nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
}
<% } -%>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
index 6480dde3c8..ce0489409c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
@@ -85,9 +85,24 @@ public class PropertyFactory {
}
<% } -%>
- public static String colorToRgbaString(@ColorInt int value) {
- return String.format(Locale.US,"rgba(%d, %d, %d, %d)",
- (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
+ /**
+ * Converts Android color int to "rbga(r, g, b, a)" String equivalent.
+ *
+ * @param color Android color int
+ * @return String rgba color
+ */
+ public static String colorToRgbaString(@ColorInt int color) {
+ return String.format(Locale.US, "rgba(%d, %d, %d, %d)",
+ (color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF);
}
+ /**
+ * Converts Android color int to rgba int array.
+ *
+ * @param color Android color int
+ * @return int rgba array
+ */
+ public static int[] colorToRgbaArray(@ColorInt int color) {
+ return new int[] {(color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, (color >> 24) & 0xFF};
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
index 7df48001cc..411c4c9652 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
@@ -9,6 +9,7 @@ import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.utils.ThreadUtils;
/**
* The global light source.
@@ -26,6 +27,7 @@ public class Light {
* @param nativePtr pointer used by core
*/
public Light(long nativePtr) {
+ checkThread();
this.nativePtr = nativePtr;
}
@@ -35,6 +37,7 @@ public class Light {
* @param anchor as String
*/
public void setAnchor(@Property.ANCHOR String anchor) {
+ checkThread();
nativeSetAnchor(anchor);
}
@@ -44,6 +47,7 @@ public class Light {
* @return anchor as String
*/
@Property.ANCHOR public String getAnchor() {
+ checkThread();
return nativeGetAnchor();
}
@@ -53,6 +57,7 @@ public class Light {
* @param position of the light
*/
public void setPosition(@NonNull Position position) {
+ checkThread();
nativeSetPosition(position);
}
@@ -62,6 +67,7 @@ public class Light {
* @return position as Position
*/
public Position getPosition() {
+ checkThread();
return nativeGetPosition();
}
@@ -71,6 +77,7 @@ public class Light {
* @return transition options for position
*/
public TransitionOptions getPositionTransition() {
+ checkThread();
return nativeGetPositionTransition();
}
@@ -80,6 +87,7 @@ public class Light {
* @param options transition options for position
*/
public void setPositionTransition(TransitionOptions options) {
+ checkThread();
nativeSetPositionTransition(options.getDuration(), options.getDelay());
}
@@ -89,6 +97,7 @@ public class Light {
* @param color as int
*/
public void setColor(@ColorInt int color) {
+ checkThread();
nativeSetColor(PropertyFactory.colorToRgbaString(color));
}
@@ -98,6 +107,7 @@ public class Light {
* @param color as String
*/
public void setColor(String color) {
+ checkThread();
nativeSetColor(color);
}
@@ -107,6 +117,7 @@ public class Light {
* @return color as String
*/
public String getColor() {
+ checkThread();
return nativeGetColor();
}
@@ -116,6 +127,7 @@ public class Light {
* @return transition options for color
*/
public TransitionOptions getColorTransition() {
+ checkThread();
return nativeGetColorTransition();
}
@@ -125,6 +137,7 @@ public class Light {
* @param options transition options for color
*/
public void setColorTransition(TransitionOptions options) {
+ checkThread();
nativeSetColorTransition(options.getDuration(), options.getDelay());
}
@@ -134,6 +147,7 @@ public class Light {
* @param intensity as Float
*/
public void setIntensity(float intensity) {
+ checkThread();
nativeSetIntensity(intensity);
}
@@ -143,6 +157,7 @@ public class Light {
* @return intensity as Float
*/
public float getIntensity() {
+ checkThread();
return nativeGetIntensity();
}
@@ -152,6 +167,7 @@ public class Light {
* @return transition options for intensity
*/
public TransitionOptions getIntensityTransition() {
+ checkThread();
return nativeGetIntensityTransition();
}
@@ -161,9 +177,14 @@ public class Light {
* @param options transition options for intensity
*/
public void setIntensityTransition(TransitionOptions options) {
+ checkThread();
nativeSetIntensityTransition(options.getDuration(), options.getDelay());
}
+ private void checkThread(){
+ ThreadUtils.checkThread("Light");
+ }
+
private native void nativeSetAnchor(String anchor);
private native String nativeGetAnchor();
private native void nativeSetPosition(Position position);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
index 80d927128d..f3e7c31a4f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
@@ -13,6 +13,7 @@ import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
+import com.mapbox.mapboxsdk.utils.ThreadUtils;
/**
* The global light source.
@@ -30,6 +31,7 @@ public class Light {
* @param nativePtr pointer used by core
*/
public Light(long nativePtr) {
+ checkThread();
this.nativePtr = nativePtr;
}
<% for (const property of properties) { -%>
@@ -41,6 +43,7 @@ public class Light {
* @param position of the light
*/
public void set<%- camelize(property.name) %>(@NonNull Position position) {
+ checkThread();
nativeSet<%- camelize(property.name) %>(position);
}
@@ -50,6 +53,7 @@ public class Light {
* @return <%- property.name %> as Position
*/
public Position get<%- camelize(property.name) %>() {
+ checkThread();
return nativeGet<%- camelize(property.name) %>();
}
<% } else { -%>
@@ -61,6 +65,7 @@ public class Light {
* @param <%- property.name %> as int
*/
public void set<%- camelize(property.name) %>(@ColorInt int <%- property.name %>) {
+ checkThread();
nativeSet<%- camelize(property.name) %>(PropertyFactory.colorToRgbaString(<%- property.name %>));
}
<% } -%>
@@ -71,6 +76,7 @@ public class Light {
* @param <%- property.name %> as <%- propertyType(property) %>
*/
public void set<%- camelize(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyJavaType(property) %> <%- property.name %>) {
+ checkThread();
nativeSet<%- camelize(property.name) %>(<%- property.name %>);
}
@@ -80,6 +86,7 @@ public class Light {
* @return <%- property.name %> as <%- propertyType(property) %>
*/
<%- propertyTypeAnnotation(property) %> public <%- propertyJavaType(property) %> get<%- camelize(property.name) %>() {
+ checkThread();
return nativeGet<%- camelize(property.name) %>();
}
<% } -%>
@@ -91,6 +98,7 @@ public class Light {
* @return transition options for <%- property.name %>
*/
public TransitionOptions get<%- camelize(property.name) %>Transition() {
+ checkThread();
return nativeGet<%- camelize(property.name) %>Transition();
}
@@ -100,11 +108,16 @@ public class Light {
* @param options transition options for <%- property.name %>
*/
public void set<%- camelize(property.name) %>Transition(TransitionOptions options) {
+ checkThread();
nativeSet<%- camelize(property.name) %>Transition(options.getDuration(), options.getDelay());
}
<% } -%>
<% } -%>
+ private void checkThread(){
+ ThreadUtils.checkThread("Light");
+ }
+
<% for (const property of properties) { -%>
<% if (property.name == "position") {-%>
private native void nativeSet<%- camelize(property.name) %>(Position position);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java
index 21a34f6064..469bfa8f39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java
@@ -49,6 +49,7 @@ public class CustomGeometrySource extends Source {
* @param options CustomGeometrySourceOptions.
*/
public CustomGeometrySource(String id, GeometryTileProvider provider, CustomGeometrySourceOptions options) {
+ super();
this.provider = provider;
executor = Executors.newFixedThreadPool(4);
initialize(id, options);
@@ -62,6 +63,7 @@ public class CustomGeometrySource extends Source {
* @param bounds The region in which features should be invalidated at all zoom levels
*/
public void invalidateRegion(LatLngBounds bounds) {
+ checkThread();
nativeInvalidateBounds(bounds);
}
@@ -74,6 +76,7 @@ public class CustomGeometrySource extends Source {
* @param y Tile Y coordinate.
*/
public void invalidateTile(int zoomLevel, int x, int y) {
+ checkThread();
nativeInvalidateTile(zoomLevel, x, y);
}
@@ -88,6 +91,7 @@ public class CustomGeometrySource extends Source {
* @param data Feature collection for the tile.
*/
public void setTileData(int zoomLevel, int x, int y, FeatureCollection data) {
+ checkThread();
nativeSetTileData(zoomLevel, x, y, data);
}
@@ -99,6 +103,7 @@ public class CustomGeometrySource extends Source {
*/
@NonNull
public List<Feature> querySourceFeatures(@Nullable Expression filter) {
+ checkThread();
Feature[] features = querySourceFeatures(filter != null ? filter.toArray() : null);
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java
index efacc18741..9ecc70e123 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java
@@ -37,6 +37,7 @@ public class GeoJsonSource extends Source {
* @param id the source id
*/
public GeoJsonSource(String id) {
+ super();
initialize(id, null);
setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>()));
}
@@ -48,6 +49,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, GeoJsonOptions options) {
+ super();
initialize(id, options);
setGeoJson(FeatureCollection.fromFeatures(new ArrayList<Feature>()));
}
@@ -59,6 +61,7 @@ public class GeoJsonSource extends Source {
* @param geoJson raw Json FeatureCollection
*/
public GeoJsonSource(String id, String geoJson) {
+ super();
if (geoJson == null || geoJson.startsWith("http")) {
throw new IllegalArgumentException("Expected a raw json body");
}
@@ -74,6 +77,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, String geoJson, GeoJsonOptions options) {
+ super();
if (geoJson == null || geoJson.startsWith("http")) {
throw new IllegalArgumentException("Expected a raw json body");
}
@@ -88,6 +92,7 @@ public class GeoJsonSource extends Source {
* @param url remote json file
*/
public GeoJsonSource(String id, URL url) {
+ super();
initialize(id, null);
nativeSetUrl(url.toExternalForm());
}
@@ -100,6 +105,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, URL url, GeoJsonOptions options) {
+ super();
initialize(id, options);
nativeSetUrl(url.toExternalForm());
}
@@ -111,6 +117,7 @@ public class GeoJsonSource extends Source {
* @param features the features
*/
public GeoJsonSource(String id, FeatureCollection features) {
+ super();
initialize(id, null);
setGeoJson(features);
}
@@ -123,6 +130,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, FeatureCollection features, GeoJsonOptions options) {
+ super();
initialize(id, options);
setGeoJson(features);
}
@@ -134,6 +142,7 @@ public class GeoJsonSource extends Source {
* @param feature the feature
*/
public GeoJsonSource(String id, Feature feature) {
+ super();
initialize(id, null);
setGeoJson(feature);
}
@@ -146,6 +155,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, Feature feature, GeoJsonOptions options) {
+ super();
initialize(id, options);
setGeoJson(feature);
}
@@ -157,6 +167,7 @@ public class GeoJsonSource extends Source {
* @param geometry the geometry
*/
public GeoJsonSource(String id, Geometry geometry) {
+ super();
initialize(id, null);
setGeoJson(geometry);
}
@@ -169,6 +180,7 @@ public class GeoJsonSource extends Source {
* @param options options
*/
public GeoJsonSource(String id, Geometry geometry, GeoJsonOptions options) {
+ super();
initialize(id, options);
setGeoJson(geometry);
}
@@ -179,6 +191,7 @@ public class GeoJsonSource extends Source {
* @param feature the GeoJSON {@link Feature} to set
*/
public void setGeoJson(Feature feature) {
+ checkThread();
nativeSetFeature(feature);
}
@@ -188,6 +201,7 @@ public class GeoJsonSource extends Source {
* @param geometry the GeoJSON {@link Geometry} to set
*/
public void setGeoJson(Geometry geometry) {
+ checkThread();
nativeSetGeometry(geometry);
}
@@ -197,6 +211,7 @@ public class GeoJsonSource extends Source {
* @param features the GeoJSON FeatureCollection
*/
public void setGeoJson(FeatureCollection features) {
+ checkThread();
nativeSetFeatureCollection(features);
}
@@ -206,6 +221,7 @@ public class GeoJsonSource extends Source {
* @param json the raw GeoJson FeatureCollection string
*/
public void setGeoJson(String json) {
+ checkThread();
nativeSetGeoJsonString(json);
}
@@ -215,6 +231,7 @@ public class GeoJsonSource extends Source {
* @param url the GeoJSON FeatureCollection url
*/
public void setUrl(URL url) {
+ checkThread();
setUrl(url.toExternalForm());
}
@@ -224,6 +241,7 @@ public class GeoJsonSource extends Source {
* @param url the GeoJSON FeatureCollection url
*/
public void setUrl(String url) {
+ checkThread();
nativeSetUrl(url);
}
@@ -232,6 +250,7 @@ public class GeoJsonSource extends Source {
*/
@Nullable
public String getUrl() {
+ checkThread();
return nativeGetUrl();
}
@@ -243,6 +262,7 @@ public class GeoJsonSource extends Source {
*/
@NonNull
public List<Feature> querySourceFeatures(@Nullable Expression filter) {
+ checkThread();
Feature[] features = querySourceFeatures(filter != null ? filter.toArray() : null);
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java
index b7679b5a16..2faf0d67ae 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java
@@ -45,6 +45,7 @@ public class ImageSource extends Source {
* @param url remote json file
*/
public ImageSource(String id, LatLngQuad coordinates, URL url) {
+ super();
initialize(id, coordinates);
setUrl(url);
}
@@ -57,6 +58,7 @@ public class ImageSource extends Source {
* @param bitmap A Bitmap image
*/
public ImageSource(String id, LatLngQuad coordinates, @NonNull android.graphics.Bitmap bitmap) {
+ super();
initialize(id, coordinates);
setImage(bitmap);
}
@@ -69,6 +71,7 @@ public class ImageSource extends Source {
* @param resourceId The resource ID of a Bitmap image
*/
public ImageSource(String id, LatLngQuad coordinates, @DrawableRes int resourceId) {
+ super();
initialize(id, coordinates);
setImage(resourceId);
}
@@ -88,6 +91,7 @@ public class ImageSource extends Source {
* @param url An image url
*/
public void setUrl(String url) {
+ checkThread();
nativeSetUrl(url);
}
@@ -97,6 +101,7 @@ public class ImageSource extends Source {
* @param bitmap A Bitmap image
*/
public void setImage(@NonNull android.graphics.Bitmap bitmap) {
+ checkThread();
nativeSetImage(bitmap);
}
@@ -106,6 +111,7 @@ public class ImageSource extends Source {
* @param resourceId The resource ID of a Bitmap image
*/
public void setImage(@DrawableRes int resourceId) throws IllegalArgumentException {
+ checkThread();
Context context = Mapbox.getApplicationContext();
Drawable drawable = ContextCompat.getDrawable(context, resourceId);
if (drawable instanceof BitmapDrawable) {
@@ -121,6 +127,7 @@ public class ImageSource extends Source {
*/
@Nullable
public String getUrl() {
+ checkThread();
return nativeGetUrl();
}
@@ -130,6 +137,7 @@ public class ImageSource extends Source {
* @param latLngQuad latitude and longitude of the four corners of the image
*/
public void setCoordinates(LatLngQuad latLngQuad) {
+ checkThread();
nativeSetCoordinates(latLngQuad);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java
index ee6fc5d7b7..0c510f7594 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java
@@ -40,6 +40,7 @@ public class RasterDemSource extends Source {
* @param url the source url
*/
public RasterDemSource(String id, String url) {
+ super();
initialize(id, url, DEFAULT_TILE_SIZE);
}
@@ -51,6 +52,7 @@ public class RasterDemSource extends Source {
* @param tileSize the tile size
*/
public RasterDemSource(String id, String url, int tileSize) {
+ super();
initialize(id, url, tileSize);
}
@@ -61,6 +63,7 @@ public class RasterDemSource extends Source {
* @param tileSet the {@link TileSet}
*/
public RasterDemSource(String id, TileSet tileSet) {
+ super();
initialize(id, tileSet.toValueObject(), DEFAULT_TILE_SIZE);
}
@@ -72,6 +75,7 @@ public class RasterDemSource extends Source {
* @param tileSize tje tile size
*/
public RasterDemSource(String id, TileSet tileSet, int tileSize) {
+ super();
initialize(id, tileSet.toValueObject(), tileSize);
}
@@ -80,6 +84,7 @@ public class RasterDemSource extends Source {
*/
@Nullable
public String getUrl() {
+ checkThread();
return nativeGetUrl();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java
index 38ed208618..f1f4cc1ff1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java
@@ -39,6 +39,7 @@ public class RasterSource extends Source {
* @param url the source url
*/
public RasterSource(String id, String url) {
+ super();
initialize(id, url, DEFAULT_TILE_SIZE);
}
@@ -50,6 +51,7 @@ public class RasterSource extends Source {
* @param tileSize the tile size
*/
public RasterSource(String id, String url, int tileSize) {
+ super();
initialize(id, url, tileSize);
}
@@ -60,6 +62,7 @@ public class RasterSource extends Source {
* @param tileSet the {@link TileSet}
*/
public RasterSource(String id, TileSet tileSet) {
+ super();
initialize(id, tileSet.toValueObject(), DEFAULT_TILE_SIZE);
}
@@ -71,6 +74,7 @@ public class RasterSource extends Source {
* @param tileSize tje tile size
*/
public RasterSource(String id, TileSet tileSet, int tileSize) {
+ super();
initialize(id, tileSet.toValueObject(), tileSize);
}
@@ -79,6 +83,7 @@ public class RasterSource extends Source {
*/
@Nullable
public String getUrl() {
+ checkThread();
return nativeGetUrl();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java
index 22b2244537..6a0939569a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java
@@ -1,9 +1,12 @@
package com.mapbox.mapboxsdk.style.sources;
+import com.mapbox.mapboxsdk.utils.ThreadUtils;
+
/**
* Base Peer class for sources. see source.hpp for the other half of the peer.
*/
public abstract class Source {
+
private long nativePtr;
/**
@@ -12,10 +15,19 @@ public abstract class Source {
* @param nativePtr - pointer to native peer
*/
public Source(long nativePtr) {
+ checkThread();
this.nativePtr = nativePtr;
}
public Source() {
+ checkThread();
+ }
+
+ /**
+ * Validates if source interaction is happening on the UI thread
+ */
+ protected void checkThread() {
+ ThreadUtils.checkThread("Source");
}
/**
@@ -24,6 +36,7 @@ public abstract class Source {
* @return the source id
*/
public String getId() {
+ checkThread();
return nativeGetId();
}
@@ -36,6 +49,7 @@ public abstract class Source {
* @return the string representation of the attribution in html format
*/
public String getAttribution() {
+ checkThread();
return nativeGetAttribution();
}
@@ -51,5 +65,4 @@ public abstract class Source {
protected native String nativeGetId();
protected native String nativeGetAttribution();
-
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java
index d82eaaa1c7..0df17572e9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java
@@ -47,6 +47,7 @@ public class VectorSource extends Source {
* @param url the url
*/
public VectorSource(String id, String url) {
+ super();
initialize(id, url);
}
@@ -57,6 +58,7 @@ public class VectorSource extends Source {
* @param tileSet the tileset
*/
public VectorSource(String id, TileSet tileSet) {
+ super();
initialize(id, tileSet.toValueObject());
}
@@ -70,6 +72,7 @@ public class VectorSource extends Source {
@NonNull
public List<Feature> querySourceFeatures(@Size(min = 1) String[] sourceLayerIds,
@Nullable Expression filter) {
+ checkThread();
Feature[] features = querySourceFeatures(
sourceLayerIds,
filter != null ? filter.toArray() : null);
@@ -81,6 +84,7 @@ public class VectorSource extends Source {
*/
@Nullable
public String getUrl() {
+ checkThread();
return nativeGetUrl();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java
new file mode 100644
index 0000000000..7dfd5ddd98
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ThreadUtils.java
@@ -0,0 +1,17 @@
+package com.mapbox.mapboxsdk.utils;
+
+import android.os.Looper;
+import com.mapbox.mapboxsdk.exceptions.CalledFromWorkerThreadException;
+
+public class ThreadUtils {
+
+ /**
+ * Validates if execution is occuring on the main thread.
+ */
+ public static void checkThread(String origin) {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ throw new CalledFromWorkerThreadException(
+ String.format("%s interactions should happen on the UI thread.",origin));
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
index 6ee5c157b9..e8d41ce2f1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
@@ -4,8 +4,6 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
-
import org.junit.Before;
import org.junit.Test;
@@ -39,13 +37,6 @@ public class MapboxTest {
assertSame(accessToken, Mapbox.getAccessToken());
}
- @Test(expected = MapboxConfigurationException.class)
- public void testGetInvalidAccessToken() {
- final String accessToken = "dummy";
- injectMapboxSingleton(accessToken);
- assertSame(accessToken, Mapbox.getAccessToken());
- }
-
@Test
public void testApplicationContext() {
injectMapboxSingleton("dummy");
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
index 1c259af2d0..e56ca559d4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
@@ -1,7 +1,6 @@
package com.mapbox.mapboxsdk.annotations;
import android.graphics.Bitmap;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index c66e4b6fda..789a1b2b37 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -357,6 +357,58 @@ public class LatLngBoundsTest {
}
@Test
+ public void intersectNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .intersect(200, 200, 0, 0);
+ }
+
+ @Test
+ public void intersectSouthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(0, 0, -10, -10)
+ .intersect(0, 0, -200, -200);
+ }
+
+ @Test
+ public void intersectSouthLessThanNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("LatSouth cannot be less than latNorth");
+
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .intersect(0, 200, 20, 0);
+ }
+
+
+ @Test
+ public void intersectEastWrapCheck() {
+
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, -150, 0, 0);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0);
+
+ LatLngBounds intersectLatLngBounds = LatLngBounds.from(10, -160, 0, 0);
+
+ assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds);
+ assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds);
+ }
+
+ @Test
+ public void intersectWestWrapCheck() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, 150);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200);
+
+ LatLngBounds intersectLatLngBounds = LatLngBounds.from(0, 0, -10, 160);
+
+ assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds);
+ assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds);
+ }
+
+ @Test
public void innerUnion() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(1, 1))
@@ -391,14 +443,176 @@ public class LatLngBoundsTest {
.include(new LatLng(-10, -160))
.build();
- assertEquals("outer union should match",
- latLngBounds1.union(latLngBounds2),
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine2() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, 170))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, 165))
+ .include(new LatLng(-10, -160))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine3() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -165))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, -170))
+ .include(new LatLng(-10, -160))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine4() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -160))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, -170))
+ .include(new LatLng(-10, -175))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
new LatLngBounds.Builder()
.include(new LatLng(10, 160))
.include(new LatLng(-10, -160))
.build());
+
+ assertEquals(union1, union2);
}
+ @Test
+ public void unionOverDateLine5() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -160))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, 170))
+ .include(new LatLng(-10, 175))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLineReturnWorldLonSpan() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, -160, -10, -10);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(10, 10, -10, 160);
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1, union2);
+ assertEquals(union1, LatLngBounds.from(10, 180, -10, -180));
+ }
+
+ @Test
+ public void unionNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .union(200, 200, 0, 0);
+ }
+
+ @Test
+ public void unionSouthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(0, 0, -10, -10)
+ .union(0, 0, -200, -200);
+ }
+
+ @Test
+ public void unionSouthLessThanNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("LatSouth cannot be less than latNorth");
+
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .union(0, 200, 20, 0);
+ }
+
+
+ @Test
+ public void unionEastWrapCheck() {
+
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, 10, 0, 0);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0);
+ LatLngBounds unionLatLngBounds = LatLngBounds.from(90, -160, 0, 0);
+
+ assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds);
+ assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds);
+ }
+
+ @Test
+ public void unionWestWrapCheck() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, -10);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200);
+
+ LatLngBounds unionLatLngBounds = LatLngBounds.from(0, 0, -90, 160);
+
+ assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds);
+ assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds);
+ }
@Test
public void northWest() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
index 45833e8556..1070a25f55 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
@@ -1,7 +1,7 @@
package com.mapbox.mapboxsdk.style.expressions;
import android.graphics.Color;
-
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import org.junit.Test;
import java.util.Arrays;
@@ -57,6 +57,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.pi;
import static com.mapbox.mapboxsdk.style.expressions.Expression.pow;
import static com.mapbox.mapboxsdk.style.expressions.Expression.product;
import static com.mapbox.mapboxsdk.style.expressions.Expression.properties;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.raw;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.round;
@@ -88,28 +89,28 @@ public class ExpressionTest {
@Test
public void testRgb() throws Exception {
- Object[] expected = new Object[] {"rgb", 0, 0, 0};
+ Object[] expected = new Object[] {"rgb", 0f, 0f, 0f};
Object[] actual = rgb(literal(0), literal(0), literal(0)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testRgbLiteral() throws Exception {
- Object[] expected = new Object[] {"rgb", 0, 0, 0};
+ Object[] expected = new Object[] {"rgb", 0f, 0f, 0f};
Object[] actual = rgb(0, 0, 0).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testRgba() throws Exception {
- Object[] expected = new Object[] {"rgba", 0, 0, 0, 1};
+ Object[] expected = new Object[] {"rgba", 0f, 0f, 0f, 1f};
Object[] actual = rgba(literal(0), literal(0), literal(0), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testRgbaLiteral() throws Exception {
- Object[] expected = new Object[] {"rgba", 0, 0, 0, 1};
+ Object[] expected = new Object[] {"rgba", 0f, 0f, 0f, 1f};
Object[] actual = rgba(0, 0, 0, 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -117,90 +118,132 @@ public class ExpressionTest {
@Test
public void testToRgba() throws Exception {
Object[] expected = new Object[] {"to-rgba", new Object[] {"to-color", "rgba(255, 0, 0, 255)"}};
- Object[] actual = toRgba(color(Color.RED)).toArray();
+ Object[] actual = toRgba(toColor(literal(PropertyFactory.colorToRgbaString(Color.RED)))).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testEq() throws Exception {
- Object[] expected = new Object[] {"==", 1, 1};
+ Object[] expected = new Object[] {"==", 1f, 1f};
Object[] actual = eq(literal(1), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testEqLiteral() throws Exception {
- Object[] expected = new Object[] {"==", 1, 1};
+ Object[] expected = new Object[] {"==", 1f, 1f};
Object[] actual = eq(literal(1), 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testEqExpression() throws Exception {
+ Object[] expected = new Object[] {"==",new Object[]{"get", "hello"}, 1f};
+ Object[] actual = eq(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testNeq() throws Exception {
- Object[] expected = new Object[] {"!=", 0, 1};
+ Object[] expected = new Object[] {"!=", 0f, 1f};
Object[] actual = neq(literal(0), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testNeqLiteral() throws Exception {
- Object[] expected = new Object[] {"!=", 0, 1};
+ Object[] expected = new Object[] {"!=", 0f, 1f};
Object[] actual = neq(literal(0), 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testNeqExpression() throws Exception {
+ Object[] expected = new Object[] {"!=",new Object[]{"get", "hello"}, 1f};
+ Object[] actual = neq(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testGt() throws Exception {
- Object[] expected = new Object[] {">", 0, 1};
+ Object[] expected = new Object[] {">", 0f, 1f};
Object[] actual = gt(literal(0), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testGtLiteral() throws Exception {
- Object[] expected = new Object[] {">", 0, 1};
+ Object[] expected = new Object[] {">", 0f, 1f};
Object[] actual = gt(literal(0), 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testGtExpression() throws Exception {
+ Object[] expected = new Object[] {">", new Object[] {"get", "hello"}, 1f};
+ Object[] actual = gt(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testLt() throws Exception {
- Object[] expected = new Object[] {"<", 1, 0};
+ Object[] expected = new Object[] {"<", 1f, 0f};
Object[] actual = lt(literal(1), literal(0)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLtLiteral() throws Exception {
- Object[] expected = new Object[] {"<", 1, 0};
+ Object[] expected = new Object[] {"<", 1f, 0f};
Object[] actual = lt(literal(1), 0).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testLtExpression() throws Exception {
+ Object[] expected = new Object[] {"<", new Object[] {"get", "hello"}, 1f};
+ Object[] actual = lt(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testGte() throws Exception {
- Object[] expected = new Object[] {">=", 1, 1};
+ Object[] expected = new Object[] {">=", 1f, 1f};
Object[] actual = gte(literal(1), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testGteLiteral() throws Exception {
- Object[] expected = new Object[] {">=", 1, 1};
+ Object[] expected = new Object[] {">=", 1f, 1f};
Object[] actual = gte(literal(1), 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testGteExpression() throws Exception {
+ Object[] expected = new Object[] {">=", new Object[] {"get", "hello"}, 1f};
+ Object[] actual = gte(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testLte() throws Exception {
- Object[] expected = new Object[] {"<=", 1, 1};
+ Object[] expected = new Object[] {"<=", 1f, 1f};
Object[] actual = lte(literal(1), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
+ public void testLteExpression() throws Exception {
+ Object[] expected = new Object[] {"<=", new Object[] {"get", "hello"}, 1f};
+ Object[] actual = lte(get("hello"), 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
public void testLteLiteral() throws Exception {
- Object[] expected = new Object[] {"<=", 1, 1};
+ Object[] expected = new Object[] {"<=", 1f, 1f};
Object[] actual = lte(literal(1), 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -368,21 +411,21 @@ public class ExpressionTest {
@Test
public void testAt() throws Exception {
- Object[] expected = new Object[] {"at", 3, new Object[] {"literal", new Object[] {"one", "two"}}};
+ Object[] expected = new Object[] {"at", 3f, new Object[] {"literal", new Object[] {"one", "two"}}};
Object[] actual = at(literal(3), literal(new Object[] {"one", "two"})).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAtLiteral() throws Exception {
- Object[] expected = new Object[] {"at", 3, new Object[] {"literal", new Object[] {"one", "two"}}};
+ Object[] expected = new Object[] {"at", 3f, new Object[] {"literal", new Object[] {"one", "two"}}};
Object[] actual = at(3, literal(new Object[] {"one", "two"})).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAtExpression() throws Exception {
- Object[] expected = new Object[] {"at", 3, new Object[] {"properties"}};
+ Object[] expected = new Object[] {"at", 3f, new Object[] {"properties"}};
Object[] actual = at(literal(3), properties()).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -501,56 +544,56 @@ public class ExpressionTest {
@Test
public void testSum() throws Exception {
- Object[] expected = new Object[] {"+", 1, 2};
+ Object[] expected = new Object[] {"+", 1f, 2f};
Object[] actual = sum(literal(1), literal(2)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSumLiteral() throws Exception {
- Object[] expected = new Object[] {"+", 1, 2};
+ Object[] expected = new Object[] {"+", 1f, 2f};
Object[] actual = sum(1, 2).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testProduct() throws Exception {
- Object[] expected = new Object[] {"*", 1, 2};
+ Object[] expected = new Object[] {"*", 1f, 2f};
Object[] actual = product(literal(1), literal(2)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testProductLiteral() throws Exception {
- Object[] expected = new Object[] {"*", 1, 2};
+ Object[] expected = new Object[] {"*", 1f, 2f};
Object[] actual = product(1, 2).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSubtract() throws Exception {
- Object[] expected = new Object[] {"-", 2, 1};
+ Object[] expected = new Object[] {"-", 2f, 1f};
Object[] actual = subtract(literal(2), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSubtractLiteral() throws Exception {
- Object[] expected = new Object[] {"-", 2, 1};
+ Object[] expected = new Object[] {"-", 2f, 1f};
Object[] actual = subtract(2, 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testDivision() throws Exception {
- Object[] expected = new Object[] {"/", 2, 1};
+ Object[] expected = new Object[] {"/", 2f, 1f};
Object[] actual = division(literal(2), literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testDivisionLiteral() throws Exception {
- Object[] expected = new Object[] {"/", 2, 1};
+ Object[] expected = new Object[] {"/", 2f, 1f};
Object[] actual = division(2, 1).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -558,203 +601,203 @@ public class ExpressionTest {
@Test
public void testDivisionWithNestedGet() throws Exception {
Object nestedGet = new Object[] {"get", "key"};
- Object[] expected = new Object[] {"/", 2, nestedGet};
+ Object[] expected = new Object[] {"/", 2f, nestedGet};
Object[] actual = division(literal(2), get(literal("key"))).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testMod() throws Exception {
- Object[] expected = new Object[] {"%", 1, 3};
+ Object[] expected = new Object[] {"%", 1f, 3f};
Object[] actual = mod(literal(1), literal(3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testModLiteral() throws Exception {
- Object[] expected = new Object[] {"%", 1, 3};
+ Object[] expected = new Object[] {"%", 1f, 3f};
Object[] actual = mod(1, 3).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testPow() throws Exception {
- Object[] expected = new Object[] {"^", 2, 3};
+ Object[] expected = new Object[] {"^", 2f, 3f};
Object[] actual = pow(literal(2), literal(3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testPowLiteral() throws Exception {
- Object[] expected = new Object[] {"^", 2, 3};
+ Object[] expected = new Object[] {"^", 2f, 3f};
Object[] actual = pow(2, 3).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSqrt() throws Exception {
- Object[] expected = new Object[] {"sqrt", 4};
+ Object[] expected = new Object[] {"sqrt", 4f};
Object[] actual = sqrt(literal(4)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSqrtLiteral() throws Exception {
- Object[] expected = new Object[] {"sqrt", 4};
+ Object[] expected = new Object[] {"sqrt", 4f};
Object[] actual = sqrt(4).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLog10() throws Exception {
- Object[] expected = new Object[] {"log10", 10};
- Object[] actual = log10(literal(10)).toArray();
+ Object[] expected = new Object[] {"log10", 10f};
+ Object[] actual = log10(literal(10f)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLog10Literal() throws Exception {
- Object[] expected = new Object[] {"log10", 10};
+ Object[] expected = new Object[] {"log10", 10f};
Object[] actual = log10(10).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLn() throws Exception {
- Object[] expected = new Object[] {"ln", 2};
+ Object[] expected = new Object[] {"ln", 2f};
Object[] actual = ln(literal(2)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLnLiteral() throws Exception {
- Object[] expected = new Object[] {"ln", 2};
+ Object[] expected = new Object[] {"ln", 2f};
Object[] actual = ln(2).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLog2() throws Exception {
- Object[] expected = new Object[] {"log2", 16};
+ Object[] expected = new Object[] {"log2", 16f};
Object[] actual = log2(literal(16)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLog2Literal() throws Exception {
- Object[] expected = new Object[] {"log2", 16};
+ Object[] expected = new Object[] {"log2", 16f};
Object[] actual = log2(16).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSin() throws Exception {
- Object[] expected = new Object[] {"sin", 45};
+ Object[] expected = new Object[] {"sin", 45f};
Object[] actual = sin(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testSinLiteral() throws Exception {
- Object[] expected = new Object[] {"sin", 45};
+ Object[] expected = new Object[] {"sin", 45f};
Object[] actual = sin(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testCos() throws Exception {
- Object[] expected = new Object[] {"cos", 45};
+ Object[] expected = new Object[] {"cos", 45f};
Object[] actual = cos(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testCosLiteral() throws Exception {
- Object[] expected = new Object[] {"cos", 45};
+ Object[] expected = new Object[] {"cos", 45f};
Object[] actual = cos(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testTan() throws Exception {
- Object[] expected = new Object[] {"tan", 45};
+ Object[] expected = new Object[] {"tan", 45f};
Object[] actual = tan(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testTanLiteral() throws Exception {
- Object[] expected = new Object[] {"tan", 45};
+ Object[] expected = new Object[] {"tan", 45f};
Object[] actual = tan(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAsin() throws Exception {
- Object[] expected = new Object[] {"asin", 45};
+ Object[] expected = new Object[] {"asin", 45f};
Object[] actual = asin(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAsinLiteral() throws Exception {
- Object[] expected = new Object[] {"asin", 45};
+ Object[] expected = new Object[] {"asin", 45f};
Object[] actual = asin(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAcos() throws Exception {
- Object[] expected = new Object[] {"acos", 45};
+ Object[] expected = new Object[] {"acos", 45f};
Object[] actual = acos(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAcosLiteral() throws Exception {
- Object[] expected = new Object[] {"acos", 45};
+ Object[] expected = new Object[] {"acos", 45f};
Object[] actual = acos(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAtan() throws Exception {
- Object[] expected = new Object[] {"atan", 45};
+ Object[] expected = new Object[] {"atan", 45f};
Object[] actual = atan(literal(45)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testAtanLiteral() throws Exception {
- Object[] expected = new Object[] {"atan", 45};
+ Object[] expected = new Object[] {"atan", 45f};
Object[] actual = atan(45).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testMin() throws Exception {
- Object[] expected = new Object[] {"min", 0, 1, 2, 3};
+ Object[] expected = new Object[] {"min", 0f, 1f, 2f, 3f};
Object[] actual = min(literal(0), literal(1), literal(2), literal(3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testMinLiteral() throws Exception {
- Object[] expected = new Object[] {"min", 0, 1, 2, 3};
+ Object[] expected = new Object[] {"min", 0f, 1f, 2f, 3f};
Object[] actual = min(0, 1, 2, 3).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testMax() throws Exception {
- Object[] expected = new Object[] {"max", 0, 1, 2, 3};
+ Object[] expected = new Object[] {"max", 0f, 1f, 2f, 3f};
Object[] actual = max(literal(0), literal(1), literal(2), literal(3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testMaxLiteral() throws Exception {
- Object[] expected = new Object[] {"max", 0, 1, 2, 3};
+ Object[] expected = new Object[] {"max", 0f, 1f, 2f, 3f};
Object[] actual = max(0, 1, 2, 3).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -833,7 +876,7 @@ public class ExpressionTest {
@Test
public void testNumber() throws Exception {
- Object[] expected = new Object[] {"number", 1};
+ Object[] expected = new Object[] {"number", 1f};
Object[] actual = number(literal(1)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -855,7 +898,7 @@ public class ExpressionTest {
@Test
public void testToString() throws Exception {
- Object[] expected = new Object[] {"to-string", 3};
+ Object[] expected = new Object[] {"to-string", 3f};
Object[] actual = Expression.toString(literal(3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -925,14 +968,14 @@ public class ExpressionTest {
@Test
public void testStepBasic() throws Exception {
- Object[] expected = new Object[] {"step", 12, 11, 0, 111, 1, 1111};
+ Object[] expected = new Object[] {"step", 12f, 11f, 0f, 111f, 1f, 1111f};
Object[] actual = step(literal(12), literal(11), literal(0), literal(111), literal(1), literal(1111)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testStepBasicLiteral() throws Exception {
- Object[] expected = new Object[] {"step", new Object[] {"get", "line-width"}, 11, 0, 111, 1, 1111};
+ Object[] expected = new Object[] {"step", new Object[] {"get", "line-width"}, 11f, 0f, 111f, 1f, 1111f};
Object[] actual = step(get("line-width"), literal(11), stop(0, 111), stop(1, 1111)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -941,7 +984,7 @@ public class ExpressionTest {
public void testStepExpression() throws Exception {
Object[] input = new Object[] {"get", "key"};
Object[] number = new Object[] {"to-number", input};
- Object[] expected = new Object[] {"step", number, 11, 0, 111, 1, 1111};
+ Object[] expected = new Object[] {"step", number, 11f, 0f, 111f, 1f, 1111f};
Object[] actual = step(toNumber(get(literal("key"))),
literal(11), literal(0), literal(111), literal(1), literal(1111)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
@@ -951,14 +994,14 @@ public class ExpressionTest {
public void testStepExpressionLiteral() throws Exception {
Object[] input = new Object[] {"get", "key"};
Object[] number = new Object[] {"to-number", input};
- Object[] expected = new Object[] {"step", number, 11, 0, 111, 1, 1111};
+ Object[] expected = new Object[] {"step", number, 11f, 0f, 111f, 1f, 1111f};
Object[] actual = step(toNumber(get("key")), literal(11), stop(0, 111), stop(1, 1111)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testLinear() throws Exception {
- Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12, 0, 1, 1, 2, 2, 3};
+ Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12f, 0f, 1f, 1f, 2f, 2f, 3f};
Object[] actual = interpolate(
linear(), literal(12),
literal(0), literal(1),
@@ -970,16 +1013,16 @@ public class ExpressionTest {
@Test
public void testLinearStops() throws Exception {
- Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12, 0, 1, 1, 2, 2, 3};
+ Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12f, 0f, 1f, 1f, 2f, 2f, 3f};
Object[] actual = interpolate(linear(), literal(12), stop(0, 1), stop(1, 2), stop(2, 3)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testExponential() throws Exception {
- Object[] exponential = new Object[] {"exponential", 12};
+ Object[] exponential = new Object[] {"exponential", 12f};
Object[] get = new Object[] {"get", "x"};
- Object[] expected = new Object[] {"interpolate", exponential, get, 0, 100, 200};
+ Object[] expected = new Object[] {"interpolate", exponential, get, 0f, 100f, 200f};
Object[] actual = interpolate(exponential(literal(12)),
get(literal("x")), literal(0), literal(100), literal(200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
@@ -987,9 +1030,9 @@ public class ExpressionTest {
@Test
public void testExponentialLiteral() throws Exception {
- Object[] exponential = new Object[] {"exponential", 12};
+ Object[] exponential = new Object[] {"exponential", 12f};
Object[] get = new Object[] {"get", "x"};
- Object[] expected = new Object[] {"interpolate", exponential, get, 0, 100, 100, 200};
+ Object[] expected = new Object[] {"interpolate", exponential, get, 0f, 100f, 100f, 200f};
Object[] actual = interpolate(exponential(12), get("x"), stop(0, 100), stop(100, 200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -999,16 +1042,16 @@ public class ExpressionTest {
Object[] getX = new Object[] {"get", "x"};
Object[] exponential = new Object[] {"exponential", getX};
Object[] getY = new Object[] {"get", "y"};
- Object[] expected = new Object[] {"interpolate", exponential, getY, 0, 100, 100, 200};
+ Object[] expected = new Object[] {"interpolate", exponential, getY, 0f, 100f, 100f, 200f};
Object[] actual = interpolate(exponential(get("x")), get("y"), stop(0, 100), stop(100, 200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@Test
public void testCubicBezier() throws Exception {
- Object[] cubicBezier = new Object[] {"cubic-bezier", 1, 1, 1, 1};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", 1f, 1f, 1f, 1f};
Object[] get = new Object[] {"get", "x"};
- Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0, 100, 100, 200};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0f, 100f, 100f, 200f};
Object[] actual = interpolate(cubicBezier(literal(1), literal(1), literal(1), literal(1)),
get(literal("x")), literal(0), literal(100), literal(100), literal(200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
@@ -1016,9 +1059,9 @@ public class ExpressionTest {
@Test
public void testCubicBezierLiteral() throws Exception {
- Object[] cubicBezier = new Object[] {"cubic-bezier", 1, 1, 1, 1};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", 1f, 1f, 1f, 1f};
Object[] get = new Object[] {"get", "x"};
- Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0, 100, 100, 200};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0f, 100f, 100f, 200f};
Object[] actual = interpolate(cubicBezier(1, 1, 1, 1), get("x"), stop(0, 100), stop(100, 200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
@@ -1028,8 +1071,8 @@ public class ExpressionTest {
Object[] getX = new Object[] {"get", "x"};
Object[] getY = new Object[] {"get", "y"};
Object[] getZ = new Object[] {"get", "z"};
- Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1, getY, 1};
- Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0, 100, 200};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1f, getY, 1f};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0f, 100f, 200f};
Object[] actual = interpolate(cubicBezier(get(literal("z")), literal(1),
get(literal("y")), literal(1)), get(literal("x")), literal(0), literal(100), literal(200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
@@ -1040,8 +1083,8 @@ public class ExpressionTest {
Object[] getX = new Object[] {"get", "x"};
Object[] getY = new Object[] {"get", "y"};
Object[] getZ = new Object[] {"get", "z"};
- Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1, getY, 1};
- Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0, 100, 100, 200};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1f, getY, 1f};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0f, 100f, 100f, 200f};
Object[] actual = interpolate(cubicBezier(get("z"), literal(1), get("y"),
literal(1)), get("x"), stop(0, 100), stop(100, 200)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
@@ -1056,14 +1099,15 @@ public class ExpressionTest {
@Test
public void testExpressionMinToString() throws Exception {
- String expected = "[\"min\", 0, 1, 2, 3]";
+ String expected = "[\"min\", 0.0, 1.0, 2.0, 3.0]";
String actual = min(0, 1, 2, 3).toString();
assertEquals("toString should match", expected, actual);
}
@Test
public void testExpressionExponentialToString() throws Exception {
- String expected = "[\"interpolate\", [\"cubic-bezier\", 1, 1, 1, 1], [\"get\", x], 0, 100, 100, 200]";
+ String expected = "[\"interpolate\", [\"cubic-bezier\", 1.0, 1.0, 1.0, 1.0],"
+ + " [\"get\", x], 0.0, 100.0, 100.0, 200.0]";
String actual = interpolate(cubicBezier(literal(1), literal(1), literal(1), literal(1)),
get(literal("x")), literal(0), literal(100), literal(100), literal(200)).toString();
assertEquals("toString should match", expected, actual);
@@ -1096,7 +1140,7 @@ public class ExpressionTest {
@Test
public void testColorConversion() {
Expression greenColor = color(0xFF00FF00);
- Object[] expected = new Object[] {"to-color", "rgba(0, 255, 0, 255)"};
+ Object[] expected = new Object[] {"rgba", 0f, 255f, 0f, 255f};
assertTrue("expression should match", Arrays.deepEquals(expected, greenColor.toArray()));
}
@@ -1165,4 +1209,67 @@ public class ExpressionTest {
Object[] actual = floor(literal(2.2f)).toArray();
assertTrue("expression should match", Arrays.deepEquals(expected, actual));
}
+
+ @Test
+ public void testRawEmpty() {
+ String raw = "[\"get\", ]";
+ Expression expected = get("");
+ assertEquals("expressions should match", raw(raw), expected);
+
+ raw = "[\"get\", key]";
+ expected = get("key");
+ assertEquals("expressions should match", raw(raw), expected);
+ }
+
+ @Test
+ public void testRawAndroidColors() {
+ Expression expected = interpolate(linear(), zoom(),
+ stop(12, step(get("stroke-width"),
+ color(Color.BLACK),
+ stop(1f, color(Color.RED)),
+ stop(2f, color(Color.WHITE)),
+ stop(3f, color(Color.BLUE))
+ )),
+ stop(15, step(get("stroke-width"),
+ color(Color.BLACK),
+ stop(1f, color(Color.YELLOW)),
+ stop(2f, color(Color.LTGRAY)),
+ stop(3f, color(Color.CYAN))
+ )),
+ stop(18, step(get("stroke-width"),
+ color(Color.BLACK),
+ stop(1f, color(Color.WHITE)),
+ stop(2f, color(Color.GRAY)),
+ stop(3f, color(Color.GREEN))
+ ))
+ );
+ assertEquals("expressions should match", expected, raw(expected.toString()));
+ }
+
+ @Test
+ public void testRawRgbaColor() {
+ Expression expected = interpolate(
+ exponential(2f), zoom(),
+ literal(5f), literal("rgba(0, 0, 0, 255)"),
+ literal(10.5f), literal("rgb(255, 0, 0)"),
+ literal(15), color(Color.GREEN),
+ literal(20), literal(PropertyFactory.colorToRgbaString(Color.BLUE)));
+ assertEquals("expressions should match", expected, raw(expected.toString()));
+ }
+
+ @Test
+ public void testRawMatchStrings() {
+ Expression expected = match(get("property"), literal(""),
+ stop("layer1", "image1"),
+ stop("layer2", "image2"));
+ assertEquals("expressions should match", expected, raw(expected.toString()));
+ }
+
+ @Test
+ public void testRawMatchNumbers() {
+ Expression expected = match(get("property"), literal(""),
+ stop("layer1", 2),
+ stop("layer2", 2.7));
+ assertEquals("expressions should match", expected, raw(expected.toString()));
+ }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 30e989c79b..80be26d3ae 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -41,6 +41,7 @@ android {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.debug
}
}
@@ -72,6 +73,7 @@ dependencies {
androidTestImplementation dependenciesList.testRules
androidTestImplementation dependenciesList.testEspressoCore
androidTestImplementation dependenciesList.testEspressoIntents
+ androidTestImplementation dependenciesList.testEspressoContrib
}
apply from: "${rootDir}/gradle/gradle-make.gradle"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
index 38fd8491a8..1dca34b95d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
@@ -634,7 +634,7 @@ public class MapboxMapTest extends BaseActivityTest {
}));
}
- private class MapboxMapAction implements ViewAction {
+ public class MapboxMapAction implements ViewAction {
private InvokeViewAction invokeViewAction;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
index 7a1fcbf5f3..89397c30eb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
@@ -16,17 +16,17 @@ public class OrientationTest extends BaseActivityTest {
@Test
public void testChangeDeviceOrientation() {
onView(isRoot()).perform(orientationLandscape());
- waitLoop(2200);
+ waitAction(2200);
onView(isRoot()).perform(orientationPortrait());
- waitLoop(2500);
+ waitAction(2500);
onView(isRoot()).perform(orientationLandscapeReverse());
- waitLoop(500);
+ waitAction(500);
onView(isRoot()).perform(orientationPortraitReverse());
- waitLoop(1250);
+ waitAction(1250);
onView(isRoot()).perform(orientationLandscape());
- waitLoop(750);
+ waitAction(750);
onView(isRoot()).perform(orientationPortrait());
- waitLoop(950);
+ waitAction(950);
onView(isRoot()).perform(orientationLandscapeReverse());
onView(isRoot()).perform(orientationPortraitReverse());
onView(isRoot()).perform(orientationLandscape());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
index 47af80cab9..5e8f3ed365 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/MapboxMapAction.java
@@ -17,7 +17,7 @@ public class MapboxMapAction implements ViewAction {
private OnInvokeActionListener invokeViewAction;
private MapboxMap mapboxMap;
- private MapboxMapAction(OnInvokeActionListener invokeViewAction, MapboxMap mapboxMap) {
+ public MapboxMapAction(OnInvokeActionListener invokeViewAction, MapboxMap mapboxMap) {
this.invokeViewAction = invokeViewAction;
this.mapboxMap = mapboxMap;
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
new file mode 100644
index 0000000000..26a3a2e4ab
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.testapp.action;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.view.View;
+
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+public final class WaitAction implements ViewAction {
+
+ private static final long DEFAULT_LOOP_TIME = 375;
+ private final long loopTime;
+
+ public WaitAction() {
+ this(DEFAULT_LOOP_TIME);
+ }
+
+ public WaitAction(long loopTime) {
+ this.loopTime = loopTime;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadForAtLeast(loopTime);
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
index 3f32443021..5480aa7a1c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
@@ -6,15 +6,14 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingResourceTimeoutException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
-import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction;
+import com.mapbox.mapboxsdk.testapp.action.WaitAction;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
import junit.framework.Assert;
-import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -67,12 +66,12 @@ public abstract class BaseActivityTest {
onView(withId(id)).check(matches(isDisplayed()));
}
- protected void waitLoop() {
- waitLoop(500);
+ protected void waitAction() {
+ waitAction(500);
}
- protected void waitLoop(long waitTime) {
- onView(withId(R.id.mapView)).perform(new LoopAction(waitTime));
+ protected void waitAction(long waitTime) {
+ onView(withId(R.id.mapView)).perform(new WaitAction(waitTime));
}
static boolean isConnected(Context context) {
@@ -82,34 +81,18 @@ public abstract class BaseActivityTest {
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
+ protected ViewInteraction onMapView() {
+ return onView(withId(R.id.mapView));
+ }
+
+ protected MapboxMapAction getMapboxMapAction(MapboxMapAction.OnInvokeActionListener onInvokeActionListener) {
+ return new MapboxMapAction(onInvokeActionListener, mapboxMap);
+ }
+
@After
public void afterTest() {
Timber.e("@After test: unregister idle resource");
Espresso.unregisterIdlingResources(idlingResource);
}
-
- private class LoopAction implements ViewAction {
-
- private long loopTime;
-
- public LoopAction(long loopTime) {
- this.loopTime = loopTime;
- }
-
- @Override
- public Matcher<View> getConstraints() {
- return isDisplayed();
- }
-
- @Override
- public String getDescription() {
- return getClass().getSimpleName();
- }
-
- @Override
- public void perform(UiController uiController, View view) {
- uiController.loopMainThreadForAtLeast(loopTime);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
index 33a946d0a1..c0bf35e3ce 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java
@@ -2,19 +2,16 @@ package com.mapbox.mapboxsdk.testapp.annotations;
import android.app.Activity;
import android.support.v4.content.res.ResourcesCompat;
-
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.IconManagerResolver;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest;
import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
-
import org.junit.Before;
import org.junit.Test;
@@ -39,104 +36,114 @@ public class IconTest extends BaseActivityTest {
}
@Test
- public void testEmpty() throws Exception {
+ public void testEmpty() {
assertTrue(iconMap.isEmpty());
}
@Test
- public void testAddSameIconMarker() throws Exception {
- Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker();
- getMapboxMap().addMarker(new MarkerOptions().position(new LatLng()));
- getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(1, iconMap.size());
- assertEquals(2, iconMap.get(defaultMarker), 0);
+ public void testAddSameIconMarker() {
+ validateTestSetup();
+ onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker();
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(1, iconMap.size());
+ assertEquals(2, iconMap.get(defaultMarker), 0);
+ }));
}
@Test
- public void testAddDifferentIconMarker() throws Exception {
- Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
- getMapboxMap().addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
- getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 2);
- assertTrue(iconMap.containsKey(icon));
- assertTrue(iconMap.get(icon) == 1);
+ public void testAddDifferentIconMarker() {
+ validateTestSetup();
+ onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
+ getMapboxMap().addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
+ getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 2);
+ assertTrue(iconMap.containsKey(icon));
+ assertTrue(iconMap.get(icon) == 1);
+ }));
}
@Test
- public void testAddRemoveIconMarker() throws Exception {
- MapboxMap mapboxMap = getMapboxMap();
-
- Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
- Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 2);
- assertTrue(iconMap.containsKey(icon));
- assertTrue(iconMap.get(icon) == 1);
-
- mapboxMap.removeMarker(marker);
- assertEquals(iconMap.size(), 1);
- assertFalse(iconMap.containsKey(icon));
+ public void testAddRemoveIconMarker() {
+ validateTestSetup();
+ onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon);
+ Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng()));
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 2);
+ assertTrue(iconMap.containsKey(icon));
+ assertTrue(iconMap.get(icon) == 1);
+
+ mapboxMap.removeMarker(marker);
+ assertEquals(iconMap.size(), 1);
+ assertFalse(iconMap.containsKey(icon));
+ }));
}
@Test
- public void testAddRemoveDefaultMarker() throws Exception {
- MapboxMap mapboxMap = getMapboxMap();
-
- Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- assertEquals(iconMap.size(), 1);
-
- mapboxMap.removeMarker(marker);
- assertEquals(iconMap.size(), 0);
-
- mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
- assertEquals(iconMap.size(), 1);
+ public void testAddRemoveDefaultMarker() {
+ validateTestSetup();
+ onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ assertEquals(iconMap.size(), 1);
+
+ mapboxMap.removeMarker(marker);
+ assertEquals(iconMap.size(), 0);
+
+ mapboxMap.addMarker(new MarkerOptions().position(new LatLng()));
+ assertEquals(iconMap.size(), 1);
+ }));
}
@Test
- public void testAddRemoveMany() throws Exception {
- Activity activity = rule.getActivity();
- MapboxMap mapboxMap = getMapboxMap();
- IconFactory iconFactory = IconFactory.getInstance(activity);
-
- // add 2 default icon markers
- Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
- Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1)));
-
- // add 4 unique icon markers
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon))
- .position(new LatLng(3, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon))
- .position(new LatLng(4, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars,
- ResourcesCompat.getColor(activity.getResources(),
- R.color.blueAccent, activity.getTheme())))
- .position(new LatLng(5, 1))
- );
- mapboxMap.addMarker(new MarkerOptions()
- .icon(iconFactory.fromResource(R.drawable.ic_android))
- .position(new LatLng(6, 1))
- );
-
- assertEquals("Amount of icons should match 5", 5, iconMap.size());
- assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0);
-
- mapboxMap.removeMarker(defaultMarkerOne);
-
- assertEquals("Amount of icons should match 5", 5, iconMap.size());
- assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0);
-
- mapboxMap.removeMarker(defaultMarkerTwo);
-
- assertEquals("Amount of icons should match 4", 4, iconMap.size());
- assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker()));
-
- mapboxMap.clear();
- assertEquals("Amount of icons should match 0", 0, iconMap.size());
+ public void testAddRemoveMany() {
+ validateTestSetup();
+ onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> {
+ Activity activity = rule.getActivity();
+ IconFactory iconFactory = IconFactory.getInstance(activity);
+
+ // add 2 default icon markers
+ Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1)));
+ Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1)));
+
+ // add 4 unique icon markers
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon))
+ .position(new LatLng(3, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon))
+ .position(new LatLng(4, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars,
+ ResourcesCompat.getColor(activity.getResources(),
+ R.color.blueAccent, activity.getTheme())))
+ .position(new LatLng(5, 1))
+ );
+ mapboxMap.addMarker(new MarkerOptions()
+ .icon(iconFactory.fromResource(R.drawable.ic_android))
+ .position(new LatLng(6, 1))
+ );
+
+ assertEquals("Amount of icons should match 5", 5, iconMap.size());
+ assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0);
+
+ mapboxMap.removeMarker(defaultMarkerOne);
+
+ assertEquals("Amount of icons should match 5", 5, iconMap.size());
+ assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0);
+
+ mapboxMap.removeMarker(defaultMarkerTwo);
+
+ assertEquals("Amount of icons should match 4", 4, iconMap.size());
+ assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker()));
+
+ mapboxMap.clear();
+ assertEquals("Amount of icons should match 0", 0, iconMap.size());
+ }));
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
index 2a510b4dc5..26aee2de98 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
@@ -62,7 +62,7 @@ public class CompassViewTest extends BaseActivityTest {
.build()
)));
onView(withId(R.id.compassView)).perform(click());
- waitLoop();
+ waitAction();
onView(withId(R.id.compassView)).check(matches(not(isDisplayed())));
invoke(mapboxMap, (uiController, mapboxMap) -> {
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java
new file mode 100644
index 0000000000..554bc988a6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java
@@ -0,0 +1,129 @@
+package com.mapbox.mapboxsdk.testapp.storage;
+
+import android.os.Looper;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.storage.FileSource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.action.WaitAction;
+import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity;
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.pressBack;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class FileSourceTest {
+
+ @Rule
+ public ActivityTestRule<FeatureOverviewActivity> rule = new ActivityTestRule<>(FeatureOverviewActivity.class);
+
+ private FileSource fileSource;
+
+ @Before
+ public void setUp() throws Exception {
+ onView(withId(R.id.recyclerView)).perform(new FileSourceCreator());
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ assertFalse("FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testActivateDeactivate() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(true));
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(false));
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testOpenCloseMapView() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withText("Simple Map")).perform(click());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ pressBack();
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testRotateMapView() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withText("Simple Map")).perform(click());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ onView(isRoot()).perform(orientationLandscape());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ pressBack();
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ private class FileSourceCreator implements ViewAction {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Creates the filesource instance on the UI thread";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ assertTrue(Looper.myLooper() == Looper.getMainLooper());
+ fileSource = FileSource.getInstance(rule.getActivity());
+ }
+ }
+
+ private class FileSourceActivator implements ViewAction {
+
+ private boolean activate;
+
+ FileSourceActivator(boolean activate) {
+ this.activate = activate;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Creates the filesource instance on the UI thread";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ assertTrue(Looper.myLooper() == Looper.getMainLooper());
+ if (activate) {
+ fileSource.activate();
+ } else {
+ fileSource.deactivate();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
index 2d16291832..2a8ac36507 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
@@ -160,4 +160,4 @@ public class BackgroundLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
index a851fde6dd..101d22a531 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
@@ -518,4 +518,4 @@ public class CircleLayerTest extends BaseActivityTest {
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
index c4ff79b053..baa8262e71 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java
@@ -177,6 +177,17 @@ public class ExpressionTest extends BaseActivityTest {
});
}
+ @Test
+ public void testLiteralProperty() {
+ validateTestSetup();
+ setupStyle();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ layer.setProperties(
+ fillColor(literal("#4286f4"))
+ );
+ });
+ }
+
private void setupStyle() {
invoke(mapboxMap, (uiController, mapboxMap) -> {
// Add a source
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
index f22956072d..84b3e7bd68 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
@@ -354,4 +354,4 @@ public class FillExtrusionLayerTest extends BaseActivityTest {
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
index bdbd8958d2..3e1cbf666d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
@@ -353,4 +353,4 @@ public class FillLayerTest extends BaseActivityTest {
assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon");
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
index 549f309e4f..3a81786df4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
@@ -237,4 +237,4 @@ public class HeatmapLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getHeatmapOpacity().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
index 1fdc6d6dab..e0121a704a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
@@ -252,4 +252,4 @@ public class HillshadeLayerTest extends BaseActivityTest {
assertEquals(layer.getHillshadeAccentColorAsInt(), Color.RED);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
index 40cf0f2927..e35f0edcc4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
@@ -545,4 +545,4 @@ public class LineLayerTest extends BaseActivityTest {
assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon");
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
index 0410d09369..6e5afdb479 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
@@ -254,4 +254,4 @@ public class RasterLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
index 62f73b1507..fe38fef253 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
@@ -1392,4 +1392,4 @@ public class SymbolLayerTest extends BaseActivityTest {
assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
index 935813899f..575f64e809 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
@@ -150,7 +150,7 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest {
assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>);
});
}
-<% if (isDataDriven(property)) { -%>
+<% if (property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven') { -%>
<% if (!(property.name.endsWith("-font")||property.name.endsWith("-offset"))) { -%>
@Test
@@ -188,4 +188,4 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest {
<% } -%>
<% } -%>
<% } -%>
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 442635f909..b78fba0aae 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -69,9 +69,9 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
- android:name=".activity.annotation.AnimatedMarkerActivity"
- android:description="@string/description_animated_marker"
- android:label="@string/activity_animated_marker">
+ android:name=".activity.annotation.AnimatedSymbolLayerActivity"
+ android:description="@string/description_animated_symbollayer"
+ android:label="@string/activity_animated_symbollayer">
<meta-data
android:name="@string/category"
android:value="@string/category_annotation" />
@@ -345,6 +345,17 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
+ android:name=".activity.snapshot.MapSnapshotterLocalStyleActivity"
+ android:description="@string/description_map_snapshotter_local_style"
+ android:label="@string/activity_map_snapshotter_local_style">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_imagegenerator" />
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity" />
+ </activity>
+ <activity
android:name=".activity.maplayout.DoubleMapActivity"
android:description="@string/description_doublemap"
android:label="@string/activity_double_map">
@@ -794,4 +805,4 @@
<!-- android:value="true" /> -->
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
index fa13959112..a06a489388 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
@@ -3,12 +3,10 @@ package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
import android.text.TextUtils;
-
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.Telemetry;
import com.mapbox.mapboxsdk.testapp.utils.TokenUtils;
import com.squareup.leakcanary.LeakCanary;
-
import timber.log.Timber;
import static timber.log.Timber.DebugTree;
@@ -30,16 +28,31 @@ public class MapboxApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
+ if (!initializeLeakCanary()) {
+ return;
+ }
+ initializeLogger();
+ initializeStrictMode();
+ initializeMapbox();
+ }
+ private boolean initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
- return;
+ return false;
}
LeakCanary.install(this);
+ return true;
+ }
- initializeLogger();
+ private void initializeLogger() {
+ if (BuildConfig.DEBUG) {
+ Timber.plant(new DebugTree());
+ }
+ }
+ private void initializeStrictMode() {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
@@ -51,20 +64,18 @@ public class MapboxApplication extends Application {
.penaltyLog()
.penaltyDeath()
.build());
+ }
- String mapboxAccessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
- if (TextUtils.isEmpty(mapboxAccessToken) || mapboxAccessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) {
- Timber.e(ACCESS_TOKEN_NOT_SET_MESSAGE);
- }
-
- Mapbox.getInstance(getApplicationContext(), mapboxAccessToken);
-
+ private void initializeMapbox() {
+ String accessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
+ validateAccessToken(accessToken);
+ Mapbox.getInstance(getApplicationContext(), accessToken);
Telemetry.updateDebugLoggingEnabled(true);
}
- private void initializeLogger() {
- if (BuildConfig.DEBUG) {
- Timber.plant(new DebugTree());
+ private static void validateAccessToken(String accessToken) {
+ if (TextUtils.isEmpty(accessToken) || accessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) {
+ Timber.e(ACCESS_TOKEN_NOT_SET_MESSAGE);
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
deleted file mode 100644
index e6db071141..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.annotation;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
-import android.os.Bundle;
-import android.support.annotation.DrawableRes;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
-import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
-import com.mapbox.turf.TurfMeasurement;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Test activity showcasing animating MarkerViews.
- */
-public class AnimatedMarkerActivity extends AppCompatActivity {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- private LatLng dupontCircle = new LatLng(38.90962, -77.04341);
-
- private Marker passengerMarker = null;
- private MarkerView carMarker = null;
-
- private Runnable animationRunnable;
-
- private List<MarkerView> markerViews = new ArrayList<>();
- private boolean stopped;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_animated_marker);
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(mapboxMap -> {
- AnimatedMarkerActivity.this.mapboxMap = mapboxMap;
- setupMap();
-
- animationRunnable = () -> {
- for (int i = 0; i < 10; i++) {
- addRandomCar();
- }
- addPassenger();
- addMainCar();
- };
- mapView.post(animationRunnable);
- });
- }
-
- private void setupMap() {
- CameraPosition cameraPosition = new CameraPosition.Builder()
- .target(dupontCircle)
- .zoom(15)
- .build();
- mapboxMap.setCameraPosition(cameraPosition);
- }
-
- private void addPassenger() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (passengerMarker == null) {
- Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_directions_run_black,
- ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme()));
- passengerMarker = mapboxMap.addMarker(new MarkerViewOptions()
- .position(randomLatLng)
- .icon(icon));
- } else {
- passengerMarker.setPosition(randomLatLng);
- }
- }
-
- private void addMainCar() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (carMarker == null) {
- carMarker = createCarMarker(randomLatLng, R.drawable.ic_taxi_top,
- markerView -> {
- // Make sure the car marker is selected so that it's always brought to the front (#5285)
- mapboxMap.selectMarker(carMarker);
- animateMoveToPassenger(carMarker);
- });
- markerViews.add(carMarker);
- } else {
- carMarker.setPosition(randomLatLng);
- }
- }
-
- private void animateMoveToPassenger(final MarkerView car) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition());
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- addPassenger();
- animateMoveToPassenger(car);
- }
- });
- }
-
- protected void addRandomCar() {
- markerViews.add(createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top,
- markerView -> randomlyMoveMarker(markerView)));
- }
-
- private void randomlyMoveMarker(final MarkerView marker) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds());
-
- // Add listener to restart animation on end
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- randomlyMoveMarker(marker);
- }
- });
- }
-
- private ValueAnimator animateMoveMarker(final MarkerView marker, LatLng to) {
- marker.setRotation((float) getBearing(marker.getPosition(), to));
-
- final ValueAnimator markerAnimator = ObjectAnimator.ofObject(
- marker, "position", new LatLngEvaluator(), marker.getPosition(), to);
- markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to)));
- markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
-
- // Start
- markerAnimator.start();
-
- return markerAnimator;
- }
-
- private MarkerView createCarMarker(LatLng start, @DrawableRes int carResource,
- MarkerViewManager.OnMarkerViewAddedListener listener) {
- Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
- .fromResource(carResource);
-
- // View Markers
- return mapboxMap.addMarker(new MarkerViewOptions()
- .position(start)
- .icon(icon), listener);
-
- // GL Markers
-// return mapboxMap.addMarker(new MarkerOptions()
-// .position(start)
-// .icon(icon));
-
- }
-
- private LatLng getLatLngInBounds() {
- LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
- Random generator = new Random();
- double randomLat = bounds.getLatSouth() + generator.nextDouble()
- * (bounds.getLatNorth() - bounds.getLatSouth());
- double randomLon = bounds.getLonWest() + generator.nextDouble()
- * (bounds.getLonEast() - bounds.getLonWest());
- return new LatLng(randomLat, randomLon);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mapView.onStart();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mapView.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mapView.onPause();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- stopped = true;
-
- // Stop ongoing animations, prevent memory leaks
- if (mapboxMap != null) {
- MarkerViewManager markerViewManager = mapboxMap.getMarkerViewManager();
- for (MarkerView markerView : markerViews) {
- View view = markerViewManager.getView(markerView);
- if (view != null) {
- view.animate().cancel();
- }
- }
- }
-
- // onStop
- mapView.onStop();
- mapView.removeCallbacks(animationRunnable);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mapView.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mapView.onDestroy();
- }
-
- @Override
- public void onLowMemory() {
- super.onLowMemory();
- mapView.onLowMemory();
- }
-
- /**
- * Evaluator for LatLng pairs
- */
- private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
-
- private LatLng latLng = new LatLng();
-
- @Override
- public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
- latLng.setLatitude(startValue.getLatitude()
- + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
- latLng.setLongitude(startValue.getLongitude()
- + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
- return latLng;
- }
- }
-
- private double getBearing(LatLng from, LatLng to) {
- return TurfMeasurement.bearing(
- Point.fromLngLat(from.getLongitude(), from.getLatitude()),
- Point.fromLngLat(to.getLongitude(), to.getLatitude())
- );
- }
-
- private boolean isActivityStopped() {
- return stopped;
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
index 6277dffe91..5983fb367a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
@@ -172,9 +172,12 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
if (mapboxMap == null) {
return false;
}
- findViewById(R.id.fab).setVisibility(View.GONE);
- resetCameraPosition();
- playAnimation(item.getItemId());
+
+ if (item.getItemId() != android.R.id.home) {
+ findViewById(R.id.fab).setVisibility(View.GONE);
+ resetCameraPosition();
+ playAnimation(item.getItemId());
+ }
return super.onOptionsItemSelected(item);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
index 930626078d..f5e0371aad 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java
@@ -1,14 +1,13 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment;
-import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
-
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapFragment;
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -20,53 +19,71 @@ import com.mapbox.mapboxsdk.testapp.R;
* Uses MapboxMapOptions to initialise the Fragment.
* </p>
*/
-public class MapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback {
+public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
+ OnMapReadyCallback, MapView.OnMapChangedListener {
private MapboxMap mapboxMap;
+ private MapView mapView;
+ private boolean initialCameraAnimation = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
-
- MapFragment mapFragment;
if (savedInstanceState == null) {
- final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ MapFragment mapFragment = MapFragment.newInstance(createFragmentOptions());
+ getFragmentManager()
+ .beginTransaction()
+ .add(R.id.fragment_container,mapFragment, "com.mapbox.map")
+ .commit();
+ mapFragment.getMapAsync(this);
+ }
+ }
- MapboxMapOptions options = new MapboxMapOptions();
- options.styleUrl(Style.OUTDOORS);
+ private MapboxMapOptions createFragmentOptions() {
+ MapboxMapOptions options = new MapboxMapOptions();
+ options.styleUrl(Style.OUTDOORS);
- options.scrollGesturesEnabled(false);
- options.zoomGesturesEnabled(false);
- options.tiltGesturesEnabled(false);
- options.rotateGesturesEnabled(false);
+ options.scrollGesturesEnabled(false);
+ options.zoomGesturesEnabled(false);
+ options.tiltGesturesEnabled(false);
+ options.rotateGesturesEnabled(false);
+ options.debugActive(false);
- options.debugActive(false);
+ LatLng dc = new LatLng(38.90252, -77.02291);
- LatLng dc = new LatLng(38.90252, -77.02291);
+ options.minZoomPreference(9);
+ options.maxZoomPreference(11);
+ options.camera(new CameraPosition.Builder()
+ .target(dc)
+ .zoom(11)
+ .build());
+ return options;
+ }
- options.minZoomPreference(9);
- options.maxZoomPreference(11);
- options.camera(new CameraPosition.Builder()
- .target(dc)
- .zoom(11)
- .build());
+ @Override
+ public void onMapViewReady(MapView map) {
+ mapView = map;
+ mapView.addOnMapChangedListener(this);
+ }
- mapFragment = MapFragment.newInstance(options);
+ @Override
+ public void onMapReady(MapboxMap map) {
+ mapboxMap = map;
+ }
- transaction.add(R.id.fragment_container, mapFragment, "com.mapbox.map");
- transaction.commit();
- } else {
- mapFragment = (MapFragment) getFragmentManager().findFragmentByTag("com.mapbox.map");
+ @Override
+ public void onMapChanged(int change) {
+ if (initialCameraAnimation && change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ mapboxMap.animateCamera(
+ CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000);
+ initialCameraAnimation = false;
}
-
- mapFragment.getMapAsync(this);
}
@Override
- public void onMapReady(MapboxMap map) {
- mapboxMap = map;
- mapboxMap.animateCamera(
- CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000);
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.removeOnMapChangedListener(this);
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
index 4f828060ee..f494a9231e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java
@@ -1,13 +1,13 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.os.Bundle;
-import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
-
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapFragment;
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -20,51 +20,71 @@ import com.mapbox.mapboxsdk.testapp.R;
* Uses MapboxMapOptions to initialise the Fragment.
* </p>
*/
-public class SupportMapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback {
+public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
+ OnMapReadyCallback, MapView.OnMapChangedListener {
private MapboxMap mapboxMap;
+ private MapView mapView;
+ private boolean initialCameraAnimation = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
-
- SupportMapFragment mapFragment;
if (savedInstanceState == null) {
- final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
-
- MapboxMapOptions options = new MapboxMapOptions();
- options.styleUrl(Style.SATELLITE_STREETS);
-
- options.debugActive(false);
- options.compassEnabled(false);
- options.attributionEnabled(false);
- options.logoEnabled(false);
+ SupportMapFragment mapFragment = SupportMapFragment.newInstance(createFragmentOptions());
+ getSupportFragmentManager()
+ .beginTransaction()
+ .add(R.id.fragment_container, mapFragment, "com.mapbox.map")
+ .commit();
+ mapFragment.getMapAsync(this);
+ }
+ }
- LatLng dc = new LatLng(38.90252, -77.02291);
+ private MapboxMapOptions createFragmentOptions() {
+ MapboxMapOptions options = new MapboxMapOptions();
+ options.styleUrl(Style.MAPBOX_STREETS);
- options.minZoomPreference(9);
- options.maxZoomPreference(11);
- options.camera(new CameraPosition.Builder()
- .target(dc)
- .zoom(11)
- .build());
+ options.scrollGesturesEnabled(false);
+ options.zoomGesturesEnabled(false);
+ options.tiltGesturesEnabled(false);
+ options.rotateGesturesEnabled(false);
+ options.debugActive(false);
- mapFragment = SupportMapFragment.newInstance(options);
+ LatLng dc = new LatLng(38.90252, -77.02291);
- transaction.add(R.id.fragment_container, mapFragment, "com.mapbox.map");
- transaction.commit();
- } else {
- mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag("com.mapbox.map");
- }
+ options.minZoomPreference(9);
+ options.maxZoomPreference(11);
+ options.camera(new CameraPosition.Builder()
+ .target(dc)
+ .zoom(11)
+ .build());
+ return options;
+ }
- mapFragment.getMapAsync(this);
+ @Override
+ public void onMapViewReady(MapView map) {
+ mapView = map;
+ mapView.addOnMapChangedListener(this);
}
@Override
public void onMapReady(MapboxMap map) {
mapboxMap = map;
- mapboxMap.animateCamera(
- CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000);
}
-}
+
+ @Override
+ public void onMapChanged(int change) {
+ if (initialCameraAnimation && change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ mapboxMap.animateCamera(
+ CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000);
+ initialCameraAnimation = false;
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.removeOnMapChangedListener(this);
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java
index c5ad467673..e1a524790d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java
@@ -14,7 +14,7 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
-
+import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.offline.OfflineRegion;
import com.mapbox.mapboxsdk.testapp.R;
@@ -27,10 +27,13 @@ import java.util.List;
/**
* Test activity showing integration of updating metadata of an OfflineRegion.
*/
-public class UpdateMetadataActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
+public class UpdateMetadataActivity extends AppCompatActivity implements AdapterView.OnItemClickListener,
+ AdapterView.OnItemLongClickListener {
private OfflineRegionMetadataAdapter adapter;
+ private MapView mapView;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -40,6 +43,7 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter
listView.setAdapter(adapter = new OfflineRegionMetadataAdapter(this));
listView.setEmptyView(findViewById(android.R.id.empty));
listView.setOnItemClickListener(this);
+ listView.setOnItemLongClickListener(this);
}
@Override
@@ -64,6 +68,18 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter
builder.show();
}
+ @Override
+ public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
+ ViewGroup container = (ViewGroup) findViewById(R.id.container);
+ container.removeAllViews();
+ container.addView(mapView = new MapView(view.getContext()));
+ mapView.setOfflineRegionDefinition(adapter.getItem(position).getDefinition());
+ mapView.onCreate(null);
+ mapView.onStart();
+ mapView.onResume();
+ return true;
+ }
+
private void updateMetadata(OfflineRegion region, byte[] metadata) {
region.updateMetadata(metadata, new OfflineRegion.OfflineRegionUpdateMetadataCallback() {
@Override
@@ -104,6 +120,16 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter
});
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mapView != null) {
+ mapView.onPause();
+ mapView.onStop();
+ mapView.onDestroy();
+ }
+ }
+
private static class OfflineRegionMetadataAdapter extends BaseAdapter {
private Context context;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java
new file mode 100644
index 0000000000..32c340b2ce
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/snapshot/MapSnapshotterLocalStyleActivity.java
@@ -0,0 +1,71 @@
+package com.mapbox.mapboxsdk.testapp.activity.snapshot;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.snapshotter.MapSnapshot;
+import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
+import timber.log.Timber;
+
+import java.io.IOException;
+
+/**
+ * Test activity showing how to use a the MapSnapshotter with a local style
+ */
+public class MapSnapshotterLocalStyleActivity extends AppCompatActivity
+ implements MapSnapshotter.SnapshotReadyCallback {
+
+ private MapSnapshotter mapSnapshotter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_map_snapshotter_marker);
+
+ final View container = findViewById(R.id.container);
+ container.getViewTreeObserver()
+ .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ //noinspection deprecation
+ container.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+
+ String styleJson;
+ try {
+ styleJson = ResourceUtils.readRawResource(MapSnapshotterLocalStyleActivity.this, R.raw.sat_style);
+ } catch (IOException exception) {
+ throw new RuntimeException(exception);
+ }
+
+ Timber.i("Starting snapshot");
+ mapSnapshotter = new MapSnapshotter(
+ getApplicationContext(),
+ new MapSnapshotter
+ .Options(Math.min(container.getMeasuredWidth(), 1024), Math.min(container.getMeasuredHeight(), 1024))
+ .withStyleJson(styleJson)
+ .withCameraPosition(new CameraPosition.Builder().target(new LatLng(52.090737, 5.121420)).zoom(18).build())
+ );
+ mapSnapshotter.start(MapSnapshotterLocalStyleActivity.this, error -> Timber.e(error));
+ }
+ });
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapSnapshotter.cancel();
+ }
+
+ @Override
+ public void onSnapshotReady(MapSnapshot snapshot) {
+ Timber.i("Snapshot ready");
+ ImageView imageView = (ImageView) findViewById(R.id.snapshot_image);
+ imageView.setImageBitmap(snapshot.getBitmap());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
index df06c9c42d..81fd2c6ff8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
@@ -5,7 +5,6 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
-
import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
@@ -16,16 +15,13 @@ import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
-
+import timber.log.Timber;
import java.util.List;
-import timber.log.Timber;
-
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
-import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
-import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
@@ -44,7 +40,6 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
private static final String BUS_MAKI_ICON_ID = "bus-11";
private static final String CAFE_MAKI_ICON_ID = "cafe-11";
private static final String KEY_PROPERTY_SELECTED = "selected";
- private static final float ZOOM_STOP_MIN_VALUE = 7.0f;
private static final float ZOOM_STOP_MAX_VALUE = 12.0f;
private MapView mapView;
@@ -103,11 +98,9 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
layer = new SymbolLayer(LAYER_ID, SOURCE_ID);
layer.setProperties(
iconImage(
- interpolate(
- linear(), zoom(),
- stop(ZOOM_STOP_MIN_VALUE, BUS_MAKI_ICON_ID),
- stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID)
- )
+ step(zoom(), literal(BUS_MAKI_ICON_ID),
+ stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID)
+ )
),
iconSize(
switchCase(
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
index 0566757d58..252af714e7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
@@ -10,9 +10,9 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:mapbox_cameraTargetLat="51.502615"
- app:mapbox_cameraTargetLng="4.972326"
- app:mapbox_cameraZoom="6"
+ app:mapbox_cameraTargetLat="38.90962"
+ app:mapbox_cameraTargetLng="-77.04341"
+ app:mapbox_cameraZoom="15"
app:mapbox_styleUrl="@string/mapbox_style_light"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml
index 1eb999caf5..501bc55743 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
+ android:id="@+id/container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index 5238176ce8..b515a4d3ae 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -19,7 +19,7 @@
<string name="description_offline">Offline Map example</string>
<string name="description_update_metadata">Update metadata example</string>
<string name="description_offline_region_delete">Delete region example</string>
- <string name="description_animated_marker">Animate the position change of a marker</string>
+ <string name="description_animated_symbollayer">Animate the position change of a symbol layer</string>
<string name="description_polyline">Add a polyline to a map</string>
<string name="description_polygon">Add a polygon to a map</string>
<string name="description_scroll_by">Scroll with pixels in x,y direction</string>
@@ -57,6 +57,7 @@
<string name="description_map_snapshotter">Show a static bitmap taken with the MapSnapshotter</string>
<string name="description_map_snapshotter_reuse">Show how to reuse a MapSnapshotter instance</string>
<string name="description_map_snapshotter_marker">Show how to add a marker to a Snapshot</string>
+ <string name="description_map_snapshotter_local_style">Show how to load a local style with a Snapshot</string>
<string name="description_camera_animator">Use Android SDK Animators to animate camera position changes</string>
<string name="description_symbol_generator">Use Android SDK Views as symbols</string>
<string name="description_textureview_debug">Use TextureView to render the map</string>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index 89ec586950..114ff38a0e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -4,7 +4,7 @@
<string name="activity_map_fragment">Map Fragment</string>
<string name="activity_multimap">Multiple Maps on Screen</string>
<string name="activity_add_bulk_markers">Add Markers In Bulk</string>
- <string name="activity_animated_marker">Animated Markers</string>
+ <string name="activity_animated_symbollayer">Animated SymbolLayer</string>
<string name="activity_dynamic_marker">Dynamic Marker</string>
<string name="activity_polyline">Polyline</string>
<string name="activity_polygon">Polygon</string>
@@ -57,6 +57,7 @@
<string name="activity_map_snapshotter">Map Snapshotter</string>
<string name="activity_map_snapshotter_reuse">Map Snapshotter Reuse</string>
<string name="activity_map_snapshotter_marker">Map Snapshot with marker</string>
+ <string name="activity_map_snapshotter_local_style">Map Snapshot with local style</string>
<string name="activity_camera_animator">Animator animation</string>
<string name="activity_symbol_generator">SymbolGenerator</string>
<string name="activity_textureview_debug">TextureView debug</string>
diff --git a/platform/android/README.md b/platform/android/README.md
index 1dbdeee343..31e0a94f2c 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -12,7 +12,7 @@ Alright. So, actually, you may be in the wrong place. From here on in, this READ
**To install and use the Mapbox Maps SDK for Android in an application, see the [Mapbox Maps SDK for Android website](https://www.mapbox.com/install/android/).**
-[![](https://www.mapbox.com/android-sdk/images/splash.png)](https://www.mapbox.com/android-sdk/)
+[![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://www.mapbox.com/android-sdk/)
### Setup environment
@@ -89,15 +89,14 @@ More information about building and distributing this project in [DISTRIBUTE.md]
#### Using the SDK snapshot
-Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example `5.2.0-SNAPSHOT` or:
+Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example, the `5.2.0-SNAPSHOT` would look like:
```java
// Mapbox SDK dependency
-compile('com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT@aar') {
- transitive = true
-}
+implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT'
```
-You need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies:
+
+You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies:
```
allprojects {
repositories {
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 16238f41c1..45cddd9688 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -5,7 +5,7 @@ buildscript {
google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.0.1'
+ classpath 'com.android.tools.build:gradle:3.1.2'
}
}
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index 77074dc82c..c25e48de05 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -10,7 +10,7 @@ set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> ruT <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
-if ((ANDROID_ABI STREQUAL "armeabi") OR (ANDROID_ABI STREQUAL "armeabi-v7a") OR (ANDROID_ABI STREQUAL "arm64-v8a") OR
+if ((ANDROID_ABI STREQUAL "armeabi-v7a") OR (ANDROID_ABI STREQUAL "arm64-v8a") OR
(ANDROID_ABI STREQUAL "x86") OR (ANDROID_ABI STREQUAL "x86_64"))
# Use Identical Code Folding on platforms that support the gold linker.
set(CMAKE_EXE_LINKER_FLAGS "-fuse-ld=gold -Wl,--icf=safe ${CMAKE_EXE_LINKER_FLAGS}")
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index c13e674271..5912ba71db 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -2,24 +2,23 @@ ext {
androidVersions = [
minSdkVersion : 14,
- targetSdkVersion : 25,
- compileSdkVersion: 25,
- buildToolsVersion: '26.0.3'
+ targetSdkVersion : 27,
+ compileSdkVersion: 27,
+ buildToolsVersion: '27.0.3'
]
versions = [
- mapboxServices : '3.0.1',
+ mapboxServices : '3.1.0',
mapboxTelemetry: '3.1.2',
mapboxGestures : '0.2.0',
- supportLib : '25.4.0',
- espresso : '3.0.1',
- testRunner : '1.0.1',
- leakCanary : '1.5.1',
- lost : '3.0.4',
+ supportLib : '27.1.1',
+ espresso : '3.0.2',
+ testRunner : '1.0.2',
+ leakCanary : '1.5.4',
junit : '4.12',
- mockito : '2.10.0',
- robolectric : '3.5.1',
- timber : '4.5.1',
+ mockito : '2.18.3',
+ robolectric : '3.8',
+ timber : '4.7.0',
okhttp : '3.10.0'
]
@@ -40,6 +39,7 @@ ext {
testRules : "com.android.support.test:rules:${versions.testRunner}",
testEspressoCore : "com.android.support.test.espresso:espresso-core:${versions.espresso}",
testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${versions.espresso}",
+ testEspressoContrib : "com.android.support.test.espresso:espresso-contrib:${versions.espresso}",
supportAnnotations : "com.android.support:support-annotations:${versions.supportLib}",
supportAppcompatV7 : "com.android.support:appcompat-v7:${versions.supportLib}",
@@ -47,11 +47,10 @@ ext {
supportDesign : "com.android.support:design:${versions.supportLib}",
supportRecyclerView : "com.android.support:recyclerview-v7:${versions.supportLib}",
- lost : "com.mapzen.android:lost:${versions.lost}",
gmsLocation : 'com.google.android.gms:play-services-location:11.0.4',
timber : "com.jakewharton.timber:timber:${versions.timber}",
okhttp3 : "com.squareup.okhttp3:okhttp:${versions.okhttp}",
leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${versions.leakCanary}",
leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${versions.leakCanary}"
]
-} \ No newline at end of file
+}
diff --git a/platform/android/gradle/gradle-dependencies-graph.gradle b/platform/android/gradle/gradle-dependencies-graph.gradle
new file mode 100644
index 0000000000..5cbc7b974f
--- /dev/null
+++ b/platform/android/gradle/gradle-dependencies-graph.gradle
@@ -0,0 +1,29 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.3.0"
+ }
+}
+
+import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
+import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
+import com.vanniktech.dependency.graph.generator.dot.GraphFormattingOptions
+import com.vanniktech.dependency.graph.generator.dot.Color
+import com.vanniktech.dependency.graph.generator.dot.Shape
+import com.vanniktech.dependency.graph.generator.dot.Style
+
+plugins.apply(DependencyGraphGeneratorPlugin)
+
+def mapboxGenerator = new Generator(
+ "mapboxLibraries", // Suffix for our Gradle task.
+ "", // Root suffix that we don't want in this case.
+ { dependency -> dependency.getModuleGroup().startsWith("com.mapbox.mapboxsdk") }, // Only want Mapbox libs.
+ { dependency -> true }, // Include transitive dependencies.
+)
+
+dependencyGraphGenerator {
+ generators = [mapboxGenerator]
+}
diff --git a/platform/android/gradle/wrapper/gradle-wrapper.properties b/platform/android/gradle/wrapper/gradle-wrapper.properties
index bf1b63c346..84af82d181 100644
--- a/platform/android/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Mon May 14 12:12:39 CEST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json
index eff7fb9cbf..d7d9c16550 100644
--- a/platform/android/scripts/exclude-activity-gen.json
+++ b/platform/android/scripts/exclude-activity-gen.json
@@ -2,6 +2,7 @@
"BaseLocationActivity",
"MapSnapshotterMarkerActivity",
"MapSnapshotterReuseActivity",
+ "MapSnapshotterLocalStyleActivity",
"LatLngBoundsActivity",
"BottomSheetActivity",
"MapSnapshotterActivity",
@@ -18,7 +19,7 @@
"LocationPickerActivity",
"GeoJsonClusteringActivity",
"RuntimeStyleTestActivity",
- "AnimatedMarkerActivity",
+ "AnimatedSymbolLayerActivity",
"ViewPagerActivity",
"MapFragmentActivity",
"SupportMapFragmentActivity",
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 3b0363cc19..05ca957974 100755
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -267,19 +267,17 @@ global.propertyValueDoc = function (property, value) {
return doc;
};
-global.isDataDriven = function (property) {
- return property['property-function'] === true;
-};
-
global.isLightProperty = function (property) {
return property['light-property'] === true;
};
global.propertyValueType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
- } else {
- return `PropertyValue<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ default:
+ return `PropertyValue<${evaluatedType(property)}>`;
}
};
@@ -318,11 +316,11 @@ global.evaluatedType = function (property) {
};
global.supportsZoomFunction = function (property) {
- return property['zoom-function'] === true;
+ return property.expression && property.expression.parameters.indexOf('zoom') > -1;
};
global.supportsPropertyFunction = function (property) {
- return property['property-function'] === true;
+ return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven';
};
// Template processing //
diff --git a/platform/android/src/bitmap.cpp b/platform/android/src/bitmap.cpp
index 46e7253050..0d3670b666 100644
--- a/platform/android/src/bitmap.cpp
+++ b/platform/android/src/bitmap.cpp
@@ -1,6 +1,7 @@
#include "bitmap.hpp"
#include <android/bitmap.h>
+#include <mbgl/util/logging.hpp>
namespace mbgl {
namespace android {
@@ -17,7 +18,7 @@ public:
~PixelGuard() {
const int result = AndroidBitmap_unlockPixels(&env, jni::Unwrap(*bitmap));
if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
- throw std::runtime_error("bitmap decoding: could not unlock pixels");
+ Log::Warning(mbgl::Event::General, "Bitmap decoding: could not unlock pixels");
}
}
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index d8d715dbd3..2a6cac3b02 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -23,7 +23,9 @@ FileSource::FileSource(jni::JNIEnv& _env,
std::make_unique<AssetManagerFileSource>(_env, assetManager));
// Set access token
- fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
+ if (accessToken) {
+ fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
+ }
}
FileSource::~FileSource() {
@@ -83,6 +85,13 @@ void FileSource::pause(jni::JNIEnv&) {
}
}
+jni::jboolean FileSource::isResumed(jni::JNIEnv&) {
+ if (activationCounter) {
+ return (jboolean) (activationCounter > 0);
+ }
+ return (jboolean) false;
+}
+
jni::Class<FileSource> FileSource::javaClass;
FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
@@ -114,7 +123,8 @@ void FileSource::registerNative(jni::JNIEnv& env) {
METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
METHOD(&FileSource::setResourceTransform, "setResourceTransform"),
METHOD(&FileSource::resume, "activate"),
- METHOD(&FileSource::pause, "deactivate")
+ METHOD(&FileSource::pause, "deactivate"),
+ METHOD(&FileSource::isResumed, "isActivated")
);
}
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 194f784622..e4295e1b84 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -45,6 +45,8 @@ public:
void pause(jni::JNIEnv&);
+ jni::jboolean isResumed(jni::JNIEnv&);
+
static jni::Class<FileSource> javaClass;
static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp
index aa9dc1a7f6..8a9656ea14 100644
--- a/platform/android/src/geojson/point.cpp
+++ b/platform/android/src/geojson/point.cpp
@@ -59,4 +59,4 @@ jni::Class<Point> Point::javaClass;
} // namespace geojson
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index 34366d836a..f655f13ea8 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -5,6 +5,7 @@
#include <mbgl/util/thread.hpp>
#include <mbgl/util/timer.hpp>
#include <mbgl/actor/scheduler.hpp>
+#include <mbgl/util/event.hpp>
#include <android/looper.h>
@@ -17,6 +18,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include <mbgl/util/logging.hpp>
#define PIPE_OUT 0
#define PIPE_IN 1
@@ -119,11 +121,11 @@ RunLoop::Impl::~Impl() {
alarm.reset();
if (ALooper_removeFd(loop, fds[PIPE_OUT]) != 1) {
- throw std::runtime_error("Failed to remove file descriptor from Looper.");
+ Log::Error(mbgl::Event::General, "Failed to remove file descriptor from Looper");
}
if (close(fds[PIPE_IN]) || close(fds[PIPE_OUT])) {
- throw std::runtime_error("Failed to close file descriptor.");
+ Log::Error(mbgl::Event::General, "Failed to close file descriptor.");
}
ALooper_release(loop);
diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp
index a006953d36..ca1307dd16 100644
--- a/platform/android/src/snapshotter/map_snapshotter.cpp
+++ b/platform/android/src/snapshotter/map_snapshotter.cpp
@@ -20,6 +20,7 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
jni::jint width,
jni::jint height,
jni::String styleURL,
+ jni::String styleJSON,
jni::Object<LatLngBounds> region,
jni::Object<CameraPosition> position,
jni::jboolean _showLogo,
@@ -42,12 +43,19 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
if (region) {
bounds = LatLngBounds::getLatLngBounds(_env, region);
}
+
+ std::pair<bool, std::string> style;
+ if (styleJSON) {
+ style = std::make_pair(true, jni::Make<std::string>(_env, styleJSON));
+ } else {
+ style = std::make_pair(false, jni::Make<std::string>(_env, styleURL));
+ }
showLogo = _showLogo;
// Create the core snapshotter
snapshotter = std::make_unique<mbgl::MapSnapshotter>(fileSource,
*threadPool,
- jni::Make<std::string>(_env, styleURL),
+ style,
size,
pixelRatio,
cameraOptions,
@@ -141,7 +149,7 @@ void MapSnapshotter::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<MapSnapshotter>(env, MapSnapshotter::javaClass, "nativePtr",
- std::make_unique<MapSnapshotter, JNIEnv&, jni::Object<MapSnapshotter>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jint, jni::String, jni::Object<LatLngBounds>, jni::Object<CameraPosition>, jni::jboolean, jni::String>,
+ std::make_unique<MapSnapshotter, JNIEnv&, jni::Object<MapSnapshotter>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jint, jni::String, jni::String, jni::Object<LatLngBounds>, jni::Object<CameraPosition>, jni::jboolean, jni::String>,
"nativeInitialize",
"finalize",
METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"),
diff --git a/platform/android/src/snapshotter/map_snapshotter.hpp b/platform/android/src/snapshotter/map_snapshotter.hpp
index 4cdf4bcf2b..33d32e01a1 100644
--- a/platform/android/src/snapshotter/map_snapshotter.hpp
+++ b/platform/android/src/snapshotter/map_snapshotter.hpp
@@ -34,6 +34,7 @@ public:
jni::jint width,
jni::jint height,
jni::String styleURL,
+ jni::String styleJSON,
jni::Object<LatLngBounds> region,
jni::Object<CameraPosition> position,
jni::jboolean showLogo,
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
index 18eccda569..e0d4755d4a 100644
--- a/platform/darwin/docs/guides/Predicates and Expressions.md
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -536,6 +536,10 @@ expression that contains references to those variables.
An input expression, then any number of argument pairs, followed by a default
expression. Each argument pair consists of a constant value followed by an
expression to produce as a result of matching that constant value.
+ If the input value is an aggregate expression, then any of the constant values within
+ that aggregate expression result in the following argument. This is shorthand for
+ specifying an argument pair for each of the constant values within that aggregate
+ expression. It is not possible to match the aggregate expression itself.
</dd>
</dl>
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index e4e4d3dcc1..9089e57ad5 100755
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -318,10 +318,11 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
doc += '* Predefined functions, including mathematical and string operators\n' +
'* Conditional expressions\n' +
'* Variable assignments and references to assigned variables\n';
- const inputVariable = property.name === 'heatmap-color' ? '$heatmapDensity' : '$zoomLevel';
- if (property["property-function"]) {
+ const inputVariable = property.expression && property['property-type'] === 'color-ramp' ?
+ '$' + camelizeWithLeadingLowercase(property.expression.parameters[0]) : '$zoomLevel';
+ if (isDataDriven(property)) {
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable and/or feature attributes\n`;
- } else if (property.function === "interpolated") {
+ } else if (property.expression && property.expression.interpolated) {
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable\n\n` +
'This property does not support applying interpolation or step functions to feature attributes.';
} else {
@@ -332,6 +333,10 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
return doc;
};
+global.isDataDriven = function (property) {
+ return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven';
+};
+
global.propertyReqs = function (property, propertiesByName, type) {
return 'This property is only applied to the style if ' + property.requires.map(function (req) {
if (typeof req === 'string') {
diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m
index 73da8ddd63..13cbebf9fd 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -64,7 +64,9 @@
[MGLAccountManager sharedManager].accessToken = accessToken;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
- [MGLMapboxEvents setupWithAccessToken:accessToken];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [MGLMapboxEvents setupWithAccessToken:accessToken];
+ });
#endif
}
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 07d10e852b..e8d6a203d0 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -16,7 +16,7 @@
@implementation MGLAttributionInfo
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
if (!htmlString) {
return @[];
}
@@ -112,7 +112,7 @@
return infos;
}
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos {
NSMutableArray *titles = [NSMutableArray arrayWithCapacity:attributionInfos.count];
for (MGLAttributionInfo *info in attributionInfos) {
NSMutableAttributedString *title = info.title.mutableCopy;
@@ -259,7 +259,7 @@
}
}
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos {
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos {
for (MGLAttributionInfo *info in infos) {
[self growArrayByAddingAttributionInfo:info];
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index c639752ac3..85c9ed796f 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN
@param fontSize The default text size in points.
@param linkColor The default link color.
*/
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos;
/**
Returns a copy of the `URL` property modified to account for the given style
@@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
@param infos An array of info objects to add to the receiver.
*/
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos;
@end
diff --git a/platform/darwin/src/MGLCompassDirectionFormatter.m b/platform/darwin/src/MGLCompassDirectionFormatter.m
index 5f0cfae6f7..1ac6a82162 100644
--- a/platform/darwin/src/MGLCompassDirectionFormatter.m
+++ b/platform/darwin/src/MGLCompassDirectionFormatter.m
@@ -15,8 +15,8 @@
}
- (NSString *)stringFromDirection:(CLLocationDirection)direction {
- static NS_ARRAY_OF(NSString *) *shortStrings;
- static NS_ARRAY_OF(NSString *) *longStrings;
+ static NSArray<NSString *> *shortStrings;
+ static NSArray<NSString *> *longStrings;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shortStrings = @[
diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h
index 068c49245c..7e0037df89 100644
--- a/platform/darwin/src/MGLComputedShapeSource.h
+++ b/platform/darwin/src/MGLComputedShapeSource.h
@@ -101,7 +101,7 @@ MGL_EXPORT
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a custom shape data source initialized with an identifier, data source, and a
@@ -120,7 +120,7 @@ MGL_EXPORT
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
/**
Invalidates all the features and properties intersecting with or contained in
diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm
index fb25eb8eb4..04734d0ef5 100644
--- a/platform/darwin/src/MGLComputedShapeSource.mm
+++ b/platform/darwin/src/MGLComputedShapeSource.mm
@@ -13,7 +13,7 @@
const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
-mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options) {
mbgl::style::CustomGeometrySource::Options sourceOptions;
if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
@@ -148,7 +148,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
@implementation MGLComputedShapeSource
-- (instancetype)initWithIdentifier:(NSString *)identifier options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(NSDictionary<MGLShapeSourceOption, id> *)options {
NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init];
requestQueue.name = [NSString stringWithFormat:@"mgl.MGLComputedShapeSource.%@", identifier];
requestQueue.qualityOfService = NSQualityOfServiceUtility;
@@ -176,7 +176,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NSDictionary<MGLShapeSourceOption, id> *)options {
if (self = [self initWithIdentifier:identifier options:options]) {
[self setDataSource:dataSource];
}
diff --git a/platform/darwin/src/MGLComputedShapeSource_Private.h b/platform/darwin/src/MGLComputedShapeSource_Private.h
index e1887caf8d..ec075e4bd7 100644
--- a/platform/darwin/src/MGLComputedShapeSource_Private.h
+++ b/platform/darwin/src/MGLComputedShapeSource_Private.h
@@ -7,6 +7,6 @@
NS_ASSUME_NONNULL_BEGIN
MGL_EXPORT
-mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index d0c9e26062..62471abb16 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -148,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
*/
-@property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes;
+@property (nonatomic, copy) NSDictionary<NSString *, id> *attributes;
/**
Returns the feature attribute for the given attribute name.
@@ -167,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN
`attributes` property, and an `id` key corresponding to the receiver’s
`identifier` property.
*/
-- (NS_DICTIONARY_OF(NSString *, id) *)geoJSONDictionary;
+- (NSDictionary<NSString *, id> *)geoJSONDictionary;
@end
@@ -252,9 +252,9 @@ MGL_EXPORT
MGL_EXPORT
@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape<MGLFeature> *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape<MGLFeature> *> *shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index ee2c71be21..02f67dca6e 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -233,7 +233,7 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
@dynamic shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
@@ -373,7 +373,7 @@ public:
}
};
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
for (const auto &feature : features) {
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
@@ -414,7 +414,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
return feature;
}
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
NSMutableDictionary *feature = [@{@"type": @"Feature",
@"properties": (attributes) ?: [NSNull null],
@"geometry": geometry} mutableCopy];
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
index 4137200b98..d4074b53ed 100644
--- a/platform/darwin/src/MGLFeature_Private.h
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
vector tile features.
*/
MGL_EXPORT
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
/**
Returns an `MGLFeature` object converted from the given mbgl::Feature
@@ -36,7 +36,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
/**
Returns an `NSDictionary` representation of an `MGLFeature`.
*/
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index ea19cf13cc..af82482c62 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -218,7 +218,8 @@ MGL_EXPORT
/**
Name of image in sprite to use for drawing image fills. For seamless patterns,
- image width and height must be a factor of two (2, 4, 8, ..., 512).
+ image width and height must be a factor of two (2, 4, 8, ..., 512). Note that
+ zoom-dependent expressions will be evaluated only at integer zoom levels.
You can set this property to an expression containing any of the following:
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 9620ec438e..1080244bdb 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -302,7 +302,10 @@ MGL_EXPORT
/**
Specifies the lengths of the alternating dashes and gaps that form the dash
pattern. The lengths are later scaled by the line width. To convert a dash
- length to points, multiply the length by the current line width.
+ length to points, multiply the length by the current line width. Note that
+ GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to
+ the expected scale. Also note that zoom-dependent expressions will be evaluated
+ only at integer zoom levels.
This property is measured in line widths.
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 6449a7fd4f..76d99a0411 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -89,7 +89,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback;
- NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo;
+ NSArray<MGLAttributionInfo *> *_attributionInfo;
}
@@ -428,6 +428,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
_mbglThreadPool = mbgl::sharedThreadPool();
std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]);
+ std::pair<bool, std::string> style = std::make_pair(false, styleURL);
// Size; taking into account the minimum texture size for OpenGL ES
// For non retina screens the ratio is 1:1 MGLSnapshotterMinimumPixelSize
@@ -454,7 +455,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
}
// Create the snapshotter
- _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, styleURL, size, pixelRatio, cameraOptions, coordinateBounds);
+ _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(*mbglFileSource, *_mbglThreadPool, style, size, pixelRatio, cameraOptions, coordinateBounds);
}
@end
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 75638fec97..d4518e3d8f 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -70,7 +70,7 @@
return _coordinates.size();
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPointCount
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPointCount
{
return [NSSet setWithObjects:@"coordinates", nil];
}
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index a1f3e686c2..ab36592634 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -199,7 +199,7 @@ MGL_EXPORT
`packs` property, observe KVO change notifications on the `packs` key path.
The initial load results in an `NSKeyValueChangeSetting` change.
*/
-@property (nonatomic, strong, readonly, nullable) NS_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readonly, nullable) NSArray<MGLOfflinePack *> *packs;
/**
Creates and registers an offline pack that downloads the resources needed to
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 4d999144e8..f4e454534d 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -32,7 +32,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
@interface MGLOfflineStorage ()
-@property (nonatomic, strong, readwrite) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readwrite) NSMutableArray<MGLOfflinePack *> *packs;
@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
@property (nonatomic, getter=isPaused) BOOL paused;
@@ -243,7 +243,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
_mbglFileSource = nullptr;
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
// Synchronize the file source’s access token with the global one in MGLAccountManager.
if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
NSString *accessToken = change[NSKeyValueChangeNewKey];
@@ -336,7 +336,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
}
- (void)reloadPacks {
- [self getPacksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflinePack *) *packs, __unused NSError * _Nullable error) {
+ [self getPacksWithCompletionHandler:^(NSArray<MGLOfflinePack *> *packs, __unused NSError * _Nullable error) {
for (MGLOfflinePack *pack in self.packs) {
[pack invalidate];
}
@@ -344,7 +344,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
}];
}
-- (void)getPacksWithCompletionHandler:(void (^)(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError * _Nullable error))completion {
+- (void)getPacksWithCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> *packs, NSError * _Nullable error))completion {
self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
NSError *error;
if (exception) {
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 190b6df9c5..810a8b78ae 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -57,7 +57,7 @@ MGL_EXPORT
If there are no interior polygons, the value of this property is `nil`.
*/
-@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons;
+@property (nonatomic, nullable, readonly) NSArray<MGLPolygon *> *interiorPolygons;
/**
Creates and returns an `MGLPolygon` object from the specified set of
@@ -82,7 +82,7 @@ MGL_EXPORT
is considered to have no interior polygons.
@return A new polygon object.
*/
-+ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NS_ARRAY_OF(MGLPolygon *) *)interiorPolygons;
++ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NSArray<MGLPolygon *> *)interiorPolygons;
@end
@@ -109,7 +109,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolygon.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readonly) NSArray<MGLPolygon *> *polygons;
/**
Creates and returns a multipolygon object consisting of the given polygons.
@@ -117,7 +117,7 @@ MGL_EXPORT
@param polygons The array of polygons defining the shape.
@return A new multipolygon object.
*/
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons;
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons;
@end
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 2af768d514..b80504707b 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -102,7 +102,7 @@
@"coordinates": self.mgl_coordinates};
}
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
+- (NSArray<id> *)mgl_coordinates {
NSMutableArray *coordinates = [NSMutableArray array];
NSMutableArray *exteriorRing = [NSMutableArray array];
@@ -128,7 +128,7 @@
@interface MGLMultiPolygon ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolygon *> *polygons;
@end
@@ -138,11 +138,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons {
return [[self alloc] initWithPolygons:polygons];
}
-- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
+- (instancetype)initWithPolygons:(NSArray<MGLPolygon *> *)polygons {
if (self = [super init]) {
_polygons = polygons;
diff --git a/platform/darwin/src/MGLPolygon_Private.h b/platform/darwin/src/MGLPolygon_Private.h
index 75afcd61f6..b006f2d77f 100644
--- a/platform/darwin/src/MGLPolygon_Private.h
+++ b/platform/darwin/src/MGLPolygon_Private.h
@@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolygon (Private)
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
+- (NSArray<id> *)mgl_coordinates;
@end
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index b1fca5bf28..8e9007686b 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -92,7 +92,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolyline.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readonly) NSArray<MGLPolyline *> *polylines;
/**
Creates and returns a multipolyline object consisting of the given polylines.
@@ -100,7 +100,7 @@ MGL_EXPORT
@param polylines The array of polylines defining the shape.
@return A new multipolyline object.
*/
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines;
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines;
@end
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 26e3518cd8..a028db8176 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -49,7 +49,7 @@
@"coordinates": self.mgl_coordinates};
}
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
+- (NSArray<id> *)mgl_coordinates {
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
for (NSUInteger index = 0; index < self.pointCount; index++) {
CLLocationCoordinate2D coordinate = self.coordinates[index];
@@ -123,7 +123,7 @@
@interface MGLMultiPolyline ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolyline *> *polylines;
@end
@@ -133,11 +133,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines {
return [[self alloc] initWithPolylines:polylines];
}
-- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
+- (instancetype)initWithPolylines:(NSArray<MGLPolyline *> *)polylines {
if (self = [super init]) {
_polylines = polylines;
diff --git a/platform/darwin/src/MGLPolyline_Private.h b/platform/darwin/src/MGLPolyline_Private.h
index 405a0c5bc9..ff4fabaa78 100644
--- a/platform/darwin/src/MGLPolyline_Private.h
+++ b/platform/darwin/src/MGLPolyline_Private.h
@@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolyline (Private)
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
+- (NSArray<id> *)mgl_coordinates;
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.h b/platform/darwin/src/MGLRasterTileSource.h
index 59b256d5e5..f27cbc285f 100644
--- a/platform/darwin/src/MGLRasterTileSource.h
+++ b/platform/darwin/src/MGLRasterTileSource.h
@@ -127,7 +127,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index 02cfef4ae8..61e9ef97fd 100644
--- a/platform/darwin/src/MGLRasterTileSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -44,7 +44,7 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
uint16_t(round(tileSize)));
}
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
uint16_t tileSize = MGLRasterTileSourceRetinaTileSize;
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
index bec482ca61..08f3276496 100644
--- a/platform/darwin/src/MGLShapeCollection.h
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -40,7 +40,7 @@ MGL_EXPORT
/**
An array of shapes forming the shape collection.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape *> *shapes;
/**
Creates and returns a shape collection consisting of the given shapes.
@@ -49,7 +49,7 @@ MGL_EXPORT
this array is copied to the new object.
@return A new shape collection object.
*/
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm
index 03cab0043f..74e78a764a 100644
--- a/platform/darwin/src/MGLShapeCollection.mm
+++ b/platform/darwin/src/MGLShapeCollection.mm
@@ -6,11 +6,11 @@
@implementation MGLShapeCollection
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes {
return [[self alloc] initWithShapes:shapes];
}
-- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
+- (instancetype)initWithShapes:(NSArray<MGLShape *> *)shapes {
if (self = [super init]) {
_shapes = shapes.copy;
}
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 6fa93476be..1fc00d4de0 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -154,7 +154,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, a shape, and dictionary of options
@@ -183,7 +183,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, an array of features, and a dictionary
@@ -210,7 +210,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
/**
Returns a shape source with an identifier, an array of shapes, and a dictionary of
@@ -238,7 +238,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
#pragma mark Accessing a Source’s Content
@@ -291,7 +291,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
@end
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index af26b7ea13..1425269012 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -21,7 +21,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @
const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options) {
auto geoJSONOptions = mbgl::style::GeoJSONOptions();
if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
@@ -92,7 +92,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
@implementation MGLShapeSource
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -101,7 +101,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NSDictionary<MGLShapeSourceOption, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -110,7 +110,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
for (id <MGLFeature> feature in features) {
if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
[NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
@@ -120,7 +120,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
return [self initWithIdentifier:identifier shape:shapeCollection options:options];
}
@@ -153,7 +153,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
mbgl::optional<mbgl::style::Filter> optionalFilter;
if (predicate) {
diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h
index 0720074d1d..83872afcbc 100644
--- a/platform/darwin/src/MGLShapeSource_Private.h
+++ b/platform/darwin/src/MGLShapeSource_Private.h
@@ -10,6 +10,6 @@ namespace mbgl {
}
MGL_EXPORT
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 6df627d7af..814a09ed21 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -241,7 +241,7 @@ MGL_EXPORT
/**
A set containing the style’s sources.
*/
-@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources;
+@property (nonatomic, strong) NSSet<__kindof MGLSource *> *sources;
/**
Values describing animated transitions to changes on a style's individual
@@ -303,7 +303,7 @@ MGL_EXPORT
The layers included in the style, arranged according to their back-to-front
ordering on the screen.
*/
-@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *layers;
+@property (nonatomic, strong) NSArray<__kindof MGLStyleLayer *> *layers;
/**
Returns a style layer with the given identifier in the current style.
@@ -417,7 +417,7 @@ MGL_EXPORT
#pragma mark Managing Style Classes
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
+@property (nonatomic) NSArray<NSString *> *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 867ac6c451..3f9bfbf8ca 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -82,8 +82,8 @@
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
-@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier;
+@property (nonatomic, readwrite, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+@property (nonatomic) NSMutableDictionary<NSString *, NSDictionary<NSObject *, MGLTextLanguage *> *> *localizedLayersByIdentifier;
@end
@@ -142,9 +142,9 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
#pragma mark Sources
-- (NS_SET_OF(__kindof MGLSource *) *)sources {
+- (NSSet<__kindof MGLSource *> *)sources {
auto rawSources = self.rawStyle->getSources();
- NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
+ NSMutableSet<__kindof MGLSource *> *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
[sources addObject:source];
@@ -152,7 +152,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return sources;
}
-- (void)setSources:(NS_SET_OF(__kindof MGLSource *) *)sources {
+- (void)setSources:(NSSet<__kindof MGLSource *> *)sources {
for (MGLSource *source in self.sources) {
[self removeSource:source];
}
@@ -225,7 +225,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
[source removeFromMapView:self.mapView];
}
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
@@ -245,10 +245,10 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
#pragma mark Style layers
-- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
+- (NSArray<__kindof MGLStyleLayer *> *)layers
{
auto layers = self.rawStyle->getLayers();
- NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
+ NSMutableArray<__kindof MGLStyleLayer *> *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayers addObject:styleLayer];
@@ -256,7 +256,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return styleLayers;
}
-- (void)setLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers {
+- (void)setLayers:(NSArray<__kindof MGLStyleLayer *> *)layers {
for (MGLStyleLayer *layer in self.layers) {
[self removeLayer:layer];
}
@@ -594,13 +594,13 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
}
}
-- (NS_SET_OF(MGLVectorTileSource *) *)mapboxStreetsSources {
+- (NSSet<MGLVectorTileSource *> *)mapboxStreetsSources {
return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorTileSource * _Nonnull source, BOOL * _Nonnull stop) {
return [source isKindOfClass:[MGLVectorTileSource class]] && source.mapboxStreets;
}];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)placeStyleLayers {
+- (NSArray<MGLStyleLayer *> *)placeStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSSet *placeSourceLayerIdentifiers = [NSSet setWithObjects:@"marine_label", @"country_label", @"state_label", @"place_label", @"water_label", @"poi_label", @"rail_station_label", @"mountain_peak_label", nil];
@@ -610,7 +610,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return [self.layers filteredArrayUsingPredicate:isPlacePredicate];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)roadStyleLayers {
+- (NSArray<MGLStyleLayer *> *)roadStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSPredicate *isPlacePredicate = [NSPredicate predicateWithBlock:^BOOL (MGLVectorStyleLayer * _Nullable layer, NSDictionary<NSString *, id> * _Nullable bindings) {
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index e7589c1f62..f3e75b492c 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -121,7 +121,7 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property["property-function"]) { -%>
+<% if (isDataDriven(property)) { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
@@ -162,11 +162,15 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property.name === 'heatmap-color') { -%>
+<% switch (property['property-type']) {
+ case 'color-ramp': -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
-<% } else if (property["property-function"]) { -%>
+<% break
+ case 'data-driven':
+ case 'cross-faded-data-driven': -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
-<% } else { -%>
+<% break
+ default: -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } -%>
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 24466b8018..1294b9ad1c 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -24,16 +24,16 @@ namespace mbgl {
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
-- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+@property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+- (void)setStyleClasses:(NSArray<NSString *> *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
@end
@interface MGLStyle (MGLStreetsAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *placeStyleLayers;
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *roadStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *placeStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *roadStyleLayers;
@end
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index b0020e4a19..667e1e66ca 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -117,6 +117,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
+
/**
Tile coordinate systems that determine how tile coordinates in tile URLs are
interpreted.
@@ -141,6 +142,18 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
MGLTileCoordinateSystemTMS
};
+
+/**
+ An `NSNumber` object containing an unsigned integer that specifies the encoding
+ formula for raster-dem tilesets. The integer corresponds to one of
+ the constants described in `MGLDEMEncoding`.
+
+ The default value for this option is `MGLDEMEncodingMapbox`.
+
+ This option is not supported by the TileJSON spec.
+ */
+extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionDEMEncoding;
+
/**
The encoding formula used to generate the raster-dem tileset
*/
@@ -199,7 +212,7 @@ MGL_EXPORT
configuration URL, this array is also empty until the configuration JSON file
is loaded.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLAttributionInfo *) *attributionInfos;
+@property (nonatomic, copy, readonly) NSArray<MGLAttributionInfo *> *attributionInfos;
@end
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index 87ac5be9c2..2fafc6fb51 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -30,11 +30,11 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption
return nil;
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
+- (NSArray<MGLAttributionInfo *> *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
return [MGLAttributionInfo attributionInfosFromHTMLString:self.attributionHTMLString
fontSize:fontSize
linkColor:linkColor];
@@ -48,7 +48,7 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption
@end
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) {
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options) {
mbgl::Tileset tileSet;
for (NSString *tileURLTemplate in tileURLTemplates) {
diff --git a/platform/darwin/src/MGLTileSource_Private.h b/platform/darwin/src/MGLTileSource_Private.h
index 0d9876d412..1b260ca86a 100644
--- a/platform/darwin/src/MGLTileSource_Private.h
+++ b/platform/darwin/src/MGLTileSource_Private.h
@@ -28,11 +28,11 @@ namespace mbgl {
@param fontSize The default text size in points, or 0 to use the default.
@param linkColor The default link color, or `nil` to use the default.
*/
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
@end
MGL_EXPORT
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options);
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index 5c32791c2f..fbc3a43ea2 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -111,23 +111,3 @@ NS_INLINE MGLTransition MGLTransitionMake(NSTimeInterval duration, NSTimeInterva
}
NS_ASSUME_NONNULL_END
-
-#ifndef NS_ARRAY_OF
- // Foundation collection classes adopted lightweight generics in iOS 9.0 and OS X 10.11 SDKs.
- #if __has_feature(objc_generics) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
- /** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */
- #define NS_ARRAY_OF(ObjectClass...) NSArray <ObjectClass>
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray <ObjectClass>
- #define NS_SET_OF(ObjectClass...) NSSet <ObjectClass>
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet <ObjectClass>
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary <ObjectClass>
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary <ObjectClass>
- #else
- #define NS_ARRAY_OF(ObjectClass...) NSArray
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray
- #define NS_SET_OF(ObjectClass...) NSSet
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary
- #endif
-#endif
diff --git a/platform/darwin/src/MGLVectorTileSource.h b/platform/darwin/src/MGLVectorTileSource.h
index 790c9d4d42..70d2f6e8ec 100644
--- a/platform/darwin/src/MGLVectorTileSource.h
+++ b/platform/darwin/src/MGLVectorTileSource.h
@@ -99,7 +99,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
@@ -138,7 +138,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features loaded by the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
@end
diff --git a/platform/darwin/src/MGLVectorTileSource.mm b/platform/darwin/src/MGLVectorTileSource.mm
index 6b9d857ad2..e55ed13060 100644
--- a/platform/darwin/src/MGLVectorTileSource.mm
+++ b/platform/darwin/src/MGLVectorTileSource.mm
@@ -27,7 +27,7 @@
return self = [super initWithPendingSource:std::move(source)];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
return self = [super initWithPendingSource:std::move(source)];
@@ -47,7 +47,7 @@
return attribution ? @(attribution->c_str()) : nil;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
mbgl::optional<std::vector<std::string>> optionalSourceLayerIDs;
if (sourceLayerIdentifiers) {
@@ -93,9 +93,9 @@ static NSArray * const MGLMapboxStreetsAlternativeLanguages = @[
@"mul", @"ar", @"de", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans",
];
-+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
++ (NSSet<NSString *> *)mapboxStreetsLanguages {
static dispatch_once_t onceToken;
- static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ static NSSet<NSString *> *mapboxStreetsLanguages;
dispatch_once(&onceToken, ^{
mapboxStreetsLanguages = [NSSet setWithArray:MGLMapboxStreetsLanguages];
});
diff --git a/platform/darwin/src/MGLVectorTileSource_Private.h b/platform/darwin/src/MGLVectorTileSource_Private.h
index 109f66a432..8d287ae4c4 100644
--- a/platform/darwin/src/MGLVectorTileSource_Private.h
+++ b/platform/darwin/src/MGLVectorTileSource_Private.h
@@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
-+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages;
++ (NSSet<NSString *> *)mapboxStreetsLanguages;
+ (nullable NSString *)preferredMapboxStreetsLanguage;
+ (nullable NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray<NSString *> *)preferencesArray;
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h
index ad5e9d5369..86dc27f22c 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.h
+++ b/platform/darwin/src/NSBundle+MGLAdditions.h
@@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (nullable NSString *)mgl_frameworkBundleIdentifier;
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary;
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary;
+ (nullable NSString *)mgl_applicationBundleIdentifier;
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index f55059324e..37f78963d3 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -26,7 +26,7 @@
return self.mgl_frameworkInfoDictionary[@"CFBundleIdentifier"];
}
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary {
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary {
NSBundle *bundle = self.mgl_frameworkBundle;
return bundle.infoDictionary;
}
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index 380215ff32..15aa71419d 100644
--- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -115,15 +115,14 @@
return @[op, leftHandPredicate.mgl_jsonExpressionObject, rightHandPredicate.mgl_jsonExpressionObject];
}
case NSInPredicateOperatorType: {
- NSMutableArray *elements = [NSMutableArray arrayWithObjects:@"match", self.leftExpression.mgl_jsonExpressionObject, nil];
- NSArray *optionsExpressions = self.rightExpression.constantValue;
- for (id object in optionsExpressions) {
- id option = ((NSExpression *)object).mgl_jsonExpressionObject;
- [elements addObject:option];
- [elements addObject:@YES];
- }
- [elements addObject:@NO];
- return elements;
+
+ NSExpression *matchExpression = [NSExpression expressionForFunction:@"MGL_MATCH"
+ arguments:@[self.leftExpression,
+ self.rightExpression,
+ [NSExpression expressionForConstantValue:@YES],
+ [NSExpression expressionForConstantValue:@NO]]];
+
+ return matchExpression.mgl_jsonExpressionObject;
}
case NSContainsPredicateOperatorType: {
NSPredicate *inPredicate = [NSComparisonPredicate predicateWithLeftExpression:self.rightExpression
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 6dde705d3c..653e3d67e6 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -403,7 +403,7 @@ static NSArray * const MGLTokenizedFunctions = @[
If no replacements take place, this method returns the original collection.
*/
-NS_ARRAY_OF(NSExpression *) *MGLCollectionByReplacingTokensWithKeyPaths(NS_ARRAY_OF(NSExpression *) *collection) {
+NSArray<NSExpression *> *MGLCollectionByReplacingTokensWithKeyPaths(NSArray<NSExpression *> *collection) {
__block NSMutableArray *upgradedCollection;
[collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
NSExpression *upgradedItem = item.mgl_expressionByReplacingTokensWithKeyPaths;
@@ -424,7 +424,7 @@ NS_ARRAY_OF(NSExpression *) *MGLCollectionByReplacingTokensWithKeyPaths(NS_ARRAY
If no replacements take place, this method returns the original stop
dictionary.
*/
-NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLStopDictionaryByReplacingTokensWithKeyPaths(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops) {
+NSDictionary<NSNumber *, NSExpression *> *MGLStopDictionaryByReplacingTokensWithKeyPaths(NSDictionary<NSNumber *, NSExpression *> *stops) {
__block NSMutableDictionary *upgradedStops;
[stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
if (![value isKindOfClass:[NSExpression class]]) {
@@ -665,11 +665,7 @@ NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLStopDictionaryByReplacingTokens
}
+ (instancetype)mgl_expressionForConditional:(nonnull NSPredicate *)conditionPredicate trueExpression:(nonnull NSExpression *)trueExpression falseExpresssion:(nonnull NSExpression *)falseExpression {
- if (@available(iOS 9.0, *)) {
- return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression:falseExpression];
- } else {
- return [NSExpression expressionForFunction:@"MGL_IF" arguments:@[[NSExpression expressionWithFormat:@"%@", conditionPredicate], trueExpression, falseExpression]];
- }
+ return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression:falseExpression];
}
+ (instancetype)mgl_expressionForSteppingExpression:(nonnull NSExpression *)steppingExpression fromExpression:(nonnull NSExpression *)minimumExpression stops:(nonnull NSExpression *)stops {
@@ -767,6 +763,11 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
NSArray *array = (NSArray *)object;
NSString *op = array.firstObject;
+ if (![op isKindOfClass:[NSString class]]) {
+ NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(array);
+ return [NSExpression expressionForFunction:@"MGL_FUNCTION" arguments:subexpressions];
+ }
+
NSArray *argumentObjects = [array subarrayWithRange:NSMakeRange(1, array.count - 1)];
NSString *functionName = MGLFunctionNamesByExpressionOperator[op];
@@ -936,19 +937,21 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
[arguments addObject:[NSExpression expressionWithMGLJSONObject:argumentObjects[index]]];
}
}
-
- if (@available(iOS 9.0, *)) {
- if (arguments.count == 3) {
- NSPredicate *conditional = [arguments.firstObject constantValue];
- return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
- }
+
+ if (arguments.count == 3) {
+ NSPredicate *conditional = [arguments.firstObject constantValue];
+ return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
}
return [NSExpression expressionForFunction:@"MGL_IF" arguments:arguments];
} else if ([op isEqualToString:@"match"]) {
NSMutableArray *optionsArray = [NSMutableArray array];
- NSEnumerator *optionsEnumerator = argumentObjects.objectEnumerator;
- while (id object = optionsEnumerator.nextObject) {
- NSExpression *option = [NSExpression expressionWithMGLJSONObject:object];
+
+ for (NSUInteger index = 0; index < argumentObjects.count; index++) {
+ NSExpression *option = [NSExpression expressionWithMGLJSONObject:argumentObjects[index]];
+ // match operators with arrays as matching values should not parse arrays as generic functions.
+ if (index > 0 && index < argumentObjects.count - 1 && !(index % 2 == 0) && [argumentObjects[index] isKindOfClass:[NSArray class]]) {
+ option = [NSExpression expressionForAggregate:MGLSubexpressionsWithJSONObjects(argumentObjects[index])];
+ }
[optionsArray addObject:option];
}
@@ -1067,7 +1070,8 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
case NSKeyPathExpressionType: {
NSArray *expressionObject;
- for (NSString *pathComponent in self.keyPath.pathComponents.reverseObjectEnumerator) {
+ NSArray *keyPath = [self.keyPath componentsSeparatedByString:@"."];
+ for (NSString *pathComponent in keyPath) {
if (expressionObject) {
expressionObject = @[@"get", pathComponent, expressionObject];
} else {
@@ -1352,7 +1356,15 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
NSArray<NSExpression *> *arguments = isAftermarketFunction ? self.arguments : self.arguments[minimumIndex].constantValue;
for (NSUInteger index = minimumIndex; index < arguments.count; index++) {
- [expressionObject addObject:arguments[index].mgl_jsonExpressionObject];
+ NSArray *argumentObject = arguments[index].mgl_jsonExpressionObject;
+ // match operators with arrays as matching values should not parse arrays using the literal operator.
+ if (index > 0 && index < arguments.count - 1 && !(index % 2 == 0)
+ && (arguments[index].expressionType == NSAggregateExpressionType ||
+ (arguments[index].expressionType == NSConstantValueExpressionType && [arguments[index].constantValue isKindOfClass:[NSArray class]]))) {
+
+ argumentObject = argumentObject.count == 2 ? argumentObject[1] : argumentObject;
+ }
+ [expressionObject addObject:argumentObject];
}
return expressionObject;
@@ -1422,7 +1434,7 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
If no localization takes place, this method returns the original collection.
*/
-NS_ARRAY_OF(NSExpression *) *MGLLocalizedCollection(NS_ARRAY_OF(NSExpression *) *collection, NSLocale * _Nullable locale) {
+NSArray<NSExpression *> *MGLLocalizedCollection(NSArray<NSExpression *> *collection, NSLocale * _Nullable locale) {
__block NSMutableArray *localizedCollection;
[collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
NSExpression *localizedItem = [item mgl_expressionLocalizedIntoLocale:locale];
@@ -1442,7 +1454,7 @@ NS_ARRAY_OF(NSExpression *) *MGLLocalizedCollection(NS_ARRAY_OF(NSExpression *)
If no localization takes place, this method returns the original stop
dictionary.
*/
-NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLLocalizedStopDictionary(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops, NSLocale * _Nullable locale) {
+NSDictionary<NSNumber *, NSExpression *> *MGLLocalizedStopDictionary(NSDictionary<NSNumber *, NSExpression *> *stops, NSLocale * _Nullable locale) {
__block NSMutableDictionary *localizedStops;
[stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
if (![value isKindOfClass:[NSExpression class]]) {
@@ -1507,16 +1519,14 @@ NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLLocalizedStopDictionary(NS_DICT
}
case NSConditionalExpressionType: {
- if (@available(iOS 9.0, *)) {
- NSExpression *trueExpression = self.trueExpression;
- NSExpression *localizedTrueExpression = [trueExpression mgl_expressionLocalizedIntoLocale:locale];
- NSExpression *falseExpression = self.falseExpression;
- NSExpression *localizedFalseExpression = [falseExpression mgl_expressionLocalizedIntoLocale:locale];
- if (localizedTrueExpression != trueExpression || localizedFalseExpression != falseExpression) {
- return [NSExpression expressionForConditional:self.predicate
- trueExpression:localizedTrueExpression
- falseExpression:localizedFalseExpression];
- }
+ NSExpression *trueExpression = self.trueExpression;
+ NSExpression *localizedTrueExpression = [trueExpression mgl_expressionLocalizedIntoLocale:locale];
+ NSExpression *falseExpression = self.falseExpression;
+ NSExpression *localizedFalseExpression = [falseExpression mgl_expressionLocalizedIntoLocale:locale];
+ if (localizedTrueExpression != trueExpression || localizedFalseExpression != falseExpression) {
+ return [NSExpression expressionForConditional:self.predicate
+ trueExpression:localizedTrueExpression
+ falseExpression:localizedFalseExpression];
}
return self;
}
diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 75c593c10b..4888c7a00f 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -26,9 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
Only supports scripts for languages used by Mapbox Streets.
- On iOS 8 or older, this will method will always return the untransliterated
- receiver.
-
@param script The four-letter code representing the name of the script, as
specified by ISO 15924.
*/
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index a61f229511..d645490eb3 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -17,14 +17,9 @@
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
NSMutableString *string = self.mutableCopy;
NSOrthography *orthography;
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
- if ([NSOrthography respondsToSelector:@selector(defaultOrthographyForLanguage:)]) {
+ if (@available(iOS 11.0, macOS 10.13.0, *)) {
orthography = [NSOrthography defaultOrthographyForLanguage:locale.localeIdentifier];
}
-#pragma clang diagnostic pop
-#endif
[string enumerateLinguisticTagsInRange:string.mgl_wholeRange scheme:NSLinguisticTagSchemeLexicalClass options:0 orthography:orthography usingBlock:^(NSString * _Nonnull tag, NSRange tokenRange, NSRange sentenceRange, BOOL * _Nonnull stop) {
NSString *word = [string substringWithRange:tokenRange];
if (word.length > 3
@@ -46,22 +41,18 @@
}
- (NSString *)mgl_stringByTransliteratingIntoScript:(NSString *)script {
- if (@available(iOS 9.0, *)) {
- NSMutableString *string = self.mutableCopy;
- NSStringTransform transform;
- if ([script isEqualToString:@"Latn"]) {
- transform = NSStringTransformToLatin;
- } else if ([script isEqualToString:@"Hans"]) {
- // No transform available.
- } else if ([script isEqualToString:@"Cyrl"]) {
- transform = @"Any-Latin; Latin-Cyrillic";
- } else if ([script isEqualToString:@"Arab"]) {
- transform = @"Any-Latin; Latin-Arabic";
- }
- return transform ? [string stringByApplyingTransform:transform reverse:NO] : string;
- } else {
- return self;
+ NSMutableString *string = self.mutableCopy;
+ NSStringTransform transform;
+ if ([script isEqualToString:@"Latn"]) {
+ transform = NSStringTransformToLatin;
+ } else if ([script isEqualToString:@"Hans"]) {
+ // No transform available.
+ } else if ([script isEqualToString:@"Cyrl"]) {
+ transform = @"Any-Latin; Latin-Cyrillic";
+ } else if ([script isEqualToString:@"Arab"]) {
+ transform = @"Any-Latin; Latin-Arabic";
}
+ return transform ? [string stringByApplyingTransform:transform reverse:NO] : string;
}
@end
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index eccc6ceece..5961b61133 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -17,7 +17,7 @@
@"<a class=\"mapbox-improve-map\" href=\"https://www.mapbox.com/map-feedback/\" target=\"_blank\">Improve this map</a>",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
@@ -67,7 +67,7 @@
CGFloat fontSize = 72;
MGLColor *color = [MGLColor redColor];
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:72
@@ -109,7 +109,7 @@
@"Hello World",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
index de8080f425..bf18b2d30e 100644
--- a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
+++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
@@ -50,13 +50,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
@"Setting backgroundColor to a camera expression should update background-color.");
XCTAssertEqualObjects(layer.backgroundColor, functionExpression,
@"backgroundColor should round-trip camera expressions.");
-
layer.backgroundColor = nil;
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@@ -103,13 +102,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
@"Setting backgroundOpacity to a camera expression should update background-opacity.");
XCTAssertEqualObjects(layer.backgroundOpacity, functionExpression,
@"backgroundOpacity should round-trip camera expressions.");
-
layer.backgroundOpacity = nil;
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@@ -156,13 +154,12 @@
{ 18, "Background Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
@"Setting backgroundPattern to a camera expression should update background-pattern.");
XCTAssertEqualObjects(layer.backgroundPattern, functionExpression,
@"backgroundPattern should round-trip camera expressions.");
-
layer.backgroundPattern = nil;
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
index d7bf2a5afd..41f7238da2 100644
--- a/platform/darwin/test/MGLCircleStyleLayerTests.mm
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -71,7 +71,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a camera expression should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, functionExpression,
@@ -102,7 +102,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
@"circleBlur should round-trip camera-data expressions.");
-
layer.circleBlur = nil;
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@@ -143,7 +142,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a camera expression should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, functionExpression,
@@ -174,7 +173,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
@"circleColor should round-trip camera-data expressions.");
-
layer.circleColor = nil;
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@@ -215,7 +213,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a camera expression should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, functionExpression,
@@ -246,7 +244,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
@"circleOpacity should round-trip camera-data expressions.");
-
layer.circleOpacity = nil;
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@@ -287,13 +284,12 @@
{ 18, mbgl::style::AlignmentType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
@"Setting circlePitchAlignment to a camera expression should update circle-pitch-alignment.");
XCTAssertEqualObjects(layer.circlePitchAlignment, functionExpression,
@"circlePitchAlignment should round-trip camera expressions.");
-
layer.circlePitchAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
@@ -331,7 +327,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a camera expression should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, functionExpression,
@@ -362,7 +358,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
@"circleRadius should round-trip camera-data expressions.");
-
layer.circleRadius = nil;
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@@ -403,13 +398,12 @@
{ 18, mbgl::style::CirclePitchScaleType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::CirclePitchScaleType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
@"Setting circleScaleAlignment to a camera expression should update circle-pitch-scale.");
XCTAssertEqualObjects(layer.circleScaleAlignment, functionExpression,
@"circleScaleAlignment should round-trip camera expressions.");
-
layer.circleScaleAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@@ -447,7 +441,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a camera expression should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, functionExpression,
@@ -478,7 +472,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
@"circleStrokeColor should round-trip camera-data expressions.");
-
layer.circleStrokeColor = nil;
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@@ -519,7 +512,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a camera expression should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, functionExpression,
@@ -550,7 +543,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
@"circleStrokeOpacity should round-trip camera-data expressions.");
-
layer.circleStrokeOpacity = nil;
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@@ -591,7 +583,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a camera expression should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, functionExpression,
@@ -622,7 +614,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
@"circleStrokeWidth should round-trip camera-data expressions.");
-
layer.circleStrokeWidth = nil;
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@@ -669,13 +660,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
@"Setting circleTranslation to a camera expression should update circle-translate.");
XCTAssertEqualObjects(layer.circleTranslation, functionExpression,
@"circleTranslation should round-trip camera expressions.");
-
layer.circleTranslation = nil;
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@@ -713,13 +703,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
@"Setting circleTranslationAnchor to a camera expression should update circle-translate-anchor.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, functionExpression,
@"circleTranslationAnchor should round-trip camera expressions.");
-
layer.circleTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLCoordinateFormatterTests.m b/platform/darwin/test/MGLCoordinateFormatterTests.m
index d693f739ec..ac083fa103 100644
--- a/platform/darwin/test/MGLCoordinateFormatterTests.m
+++ b/platform/darwin/test/MGLCoordinateFormatterTests.m
@@ -24,12 +24,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°54′48″N, 77°1′57″W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°54′48″ north, 77°1′57″ west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s), 54 minute(s), and 48 second(s) north by 77 degree(s), 1 minute(s), and 57 second(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
shortFormatter.allowsSeconds = NO;
mediumFormatter.allowsSeconds = NO;
@@ -38,12 +33,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°55′N, 77°2′W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°55′ north, 77°2′ west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s) and 55 minute(s) north by 77 degree(s) and 2 minute(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
shortFormatter.allowsMinutes = NO;
mediumFormatter.allowsMinutes = NO;
@@ -52,12 +42,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"39°N, 77°W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"39° north, 77° west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degree(s) north by 77 degree(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
}
@end
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 4ed1f61eb1..8870618cef 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -306,6 +306,18 @@ using namespace std::string_literals;
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
+ {
+ NSExpression *expression = [NSExpression expressionForKeyPath:@"lineStyle.color"];
+ NSArray *jsonExpression = @[@"get", @"color", @[@"get", @"lineStyle"]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionForKeyPath:@"map.box.gl"];
+ NSArray *jsonExpression = @[@"get", @"gl", @[@"get", @"box", @[@"get", @"map"]]];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
}
- (void)testStatisticalExpressionObject {
@@ -777,6 +789,12 @@ using namespace std::string_literals;
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_MATCH(x, {'a', 'A'}, 'Apple', {'b', 'B'}, 'Banana', 'Kumquat')"];
+ NSArray *jsonExpression = @[@"match", @[@"get", @"x"], @[@"a", @"A"], @"Apple", @[@"b", @"B"], @"Banana", @"Kumquat"];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
}
- (void)testCoalesceExpressionObject {
@@ -799,30 +817,26 @@ using namespace std::string_literals;
}
- (void)testConditionalExpressionObject {
- // This test crashes on iOS 8, which doesn't have `+[NSExpression expressionForConditional:trueExpression:falseExpression:]`.
- // https://github.com/mapbox/mapbox-gl-native/issues/11007
- if (@available(iOS 9.0, *)) {
- {
- NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
- NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
- NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
- NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
- NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
- XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
- XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
- }
- {
- NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
- NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
- XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
- MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
- MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
- XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
- }
+ {
+ NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
+ NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
+ NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
+ NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
+ NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
{
NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, %@, %@)",
@@ -833,9 +847,7 @@ using namespace std::string_literals;
NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
}
@@ -944,12 +956,7 @@ using namespace std::string_literals;
}
{
NSExpression *expression;
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
- } else {
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
- MGLConstantExpression([NSPredicate predicateWithFormat:@"key != nil"])];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key"], [NSNull null]], @1, @0];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
@@ -959,13 +966,7 @@ using namespace std::string_literals;
{
NSDictionary *dictionary = @{@"key": @"🔑"};
NSExpression *expression;
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
- } else {
- NSPredicate *conditional = [NSPredicate predicateWithFormat:@"%@.key != nil", dictionary];
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
- MGLConstantExpression(conditional)];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key", @[@"literal", dictionary]], [NSNull null]], @1, @0];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
// The dictionary isn’t equal enough.
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index 14b64be854..d135b018f4 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -38,7 +38,7 @@
};
features.push_back(mbgl::Feature { polygon });
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0];
@@ -69,7 +69,7 @@
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 4)]);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[3]],
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 1)]);
- NS_ARRAY_OF(MGLPolygon *) *interiorPolygons = polygonShape.interiorPolygons;
+ NSArray<MGLPolygon *> *interiorPolygons = polygonShape.interiorPolygons;
XCTAssertEqual(interiorPolygons.count, 1);
MGLPolygon *interiorPolygon = interiorPolygons.firstObject;
XCTAssertEqual(interiorPolygon.pointCount, 4);
@@ -103,7 +103,7 @@
vector.push_back(true);
features.push_back(pointFeature);
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes");
MGLShape <MGLFeature> *shape = shapes.firstObject;
diff --git a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
index 6081d104e1..ac858d0edc 100644
--- a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
@@ -71,7 +71,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
@"Setting fillExtrusionBase to a camera expression should update fill-extrusion-base.");
XCTAssertEqualObjects(layer.fillExtrusionBase, functionExpression,
@@ -102,7 +102,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionBase, pedanticFunctionExpression,
@"fillExtrusionBase should round-trip camera-data expressions.");
-
layer.fillExtrusionBase = nil;
XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
@@ -143,7 +142,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
@"Setting fillExtrusionColor to a camera expression should update fill-extrusion-color.");
XCTAssertEqualObjects(layer.fillExtrusionColor, functionExpression,
@@ -174,7 +173,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionColor, pedanticFunctionExpression,
@"fillExtrusionColor should round-trip camera-data expressions.");
-
layer.fillExtrusionColor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
@@ -215,7 +213,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
@"Setting fillExtrusionHeight to a camera expression should update fill-extrusion-height.");
XCTAssertEqualObjects(layer.fillExtrusionHeight, functionExpression,
@@ -246,7 +244,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionHeight, pedanticFunctionExpression,
@"fillExtrusionHeight should round-trip camera-data expressions.");
-
layer.fillExtrusionHeight = nil;
XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
@@ -287,13 +284,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
@"Setting fillExtrusionOpacity to a camera expression should update fill-extrusion-opacity.");
XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionExpression,
@"fillExtrusionOpacity should round-trip camera expressions.");
-
layer.fillExtrusionOpacity = nil;
XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
@@ -340,13 +336,12 @@
{ 18, "Fill Extrusion Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
@"Setting fillExtrusionPattern to a camera expression should update fill-extrusion-pattern.");
XCTAssertEqualObjects(layer.fillExtrusionPattern, functionExpression,
@"fillExtrusionPattern should round-trip camera expressions.");
-
layer.fillExtrusionPattern = nil;
XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
@@ -399,13 +394,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
@"Setting fillExtrusionTranslation to a camera expression should update fill-extrusion-translate.");
XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionExpression,
@"fillExtrusionTranslation should round-trip camera expressions.");
-
layer.fillExtrusionTranslation = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
@@ -443,13 +437,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
@"Setting fillExtrusionTranslationAnchor to a camera expression should update fill-extrusion-translate-anchor.");
XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionExpression,
@"fillExtrusionTranslationAnchor should round-trip camera expressions.");
-
layer.fillExtrusionTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm
index a5019f1032..45bae07f43 100644
--- a/platform/darwin/test/MGLFillStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, false },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
@"Setting fillAntialiased to a camera expression should update fill-antialias.");
XCTAssertEqualObjects(layer.fillAntialiased, functionExpression,
@"fillAntialiased should round-trip camera expressions.");
-
layer.fillAntialiased = nil;
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@@ -115,7 +114,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
@"Setting fillColor to a camera expression should update fill-color.");
XCTAssertEqualObjects(layer.fillColor, functionExpression,
@@ -146,7 +145,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillColor, pedanticFunctionExpression,
@"fillColor should round-trip camera-data expressions.");
-
layer.fillColor = nil;
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@@ -187,7 +185,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
@"Setting fillOpacity to a camera expression should update fill-opacity.");
XCTAssertEqualObjects(layer.fillOpacity, functionExpression,
@@ -218,7 +216,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillOpacity, pedanticFunctionExpression,
@"fillOpacity should round-trip camera-data expressions.");
-
layer.fillOpacity = nil;
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@@ -259,7 +256,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
@"Setting fillOutlineColor to a camera expression should update fill-outline-color.");
XCTAssertEqualObjects(layer.fillOutlineColor, functionExpression,
@@ -290,7 +287,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillOutlineColor, pedanticFunctionExpression,
@"fillOutlineColor should round-trip camera-data expressions.");
-
layer.fillOutlineColor = nil;
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@@ -331,13 +327,12 @@
{ 18, "Fill Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
@"Setting fillPattern to a camera expression should update fill-pattern.");
XCTAssertEqualObjects(layer.fillPattern, functionExpression,
@"fillPattern should round-trip camera expressions.");
-
layer.fillPattern = nil;
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@@ -390,13 +385,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
@"Setting fillTranslation to a camera expression should update fill-translate.");
XCTAssertEqualObjects(layer.fillTranslation, functionExpression,
@"fillTranslation should round-trip camera expressions.");
-
layer.fillTranslation = nil;
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@@ -434,13 +428,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
@"Setting fillTranslationAnchor to a camera expression should update fill-translate-anchor.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, functionExpression,
@"fillTranslationAnchor should round-trip camera expressions.");
-
layer.fillTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLHeatmapStyleLayerTests.mm b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
index e4b1917257..db15778872 100644
--- a/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
+++ b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
@"Setting heatmapIntensity to a camera expression should update heatmap-intensity.");
XCTAssertEqualObjects(layer.heatmapIntensity, functionExpression,
@"heatmapIntensity should round-trip camera expressions.");
-
layer.heatmapIntensity = nil;
XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
@@ -124,13 +123,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
@"Setting heatmapOpacity to a camera expression should update heatmap-opacity.");
XCTAssertEqualObjects(layer.heatmapOpacity, functionExpression,
@"heatmapOpacity should round-trip camera expressions.");
-
layer.heatmapOpacity = nil;
XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
@@ -177,7 +175,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a camera expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
@@ -208,7 +206,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.heatmapRadius, pedanticFunctionExpression,
@"heatmapRadius should round-trip camera-data expressions.");
-
layer.heatmapRadius = nil;
XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
@@ -249,7 +246,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a camera expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
@@ -280,7 +277,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.heatmapWeight, pedanticFunctionExpression,
@"heatmapWeight should round-trip camera-data expressions.");
-
layer.heatmapWeight = nil;
XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
diff --git a/platform/darwin/test/MGLHillshadeStyleLayerTests.mm b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
index 34937d1674..2495b32d97 100644
--- a/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
+++ b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
@@ -53,13 +53,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeAccentColor(), propertyValue,
@"Setting hillshadeAccentColor to a camera expression should update hillshade-accent-color.");
XCTAssertEqualObjects(layer.hillshadeAccentColor, functionExpression,
@"hillshadeAccentColor should round-trip camera expressions.");
-
layer.hillshadeAccentColor = nil;
XCTAssertTrue(rawLayer->getHillshadeAccentColor().isUndefined(),
@@ -106,13 +105,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeExaggeration(), propertyValue,
@"Setting hillshadeExaggeration to a camera expression should update hillshade-exaggeration.");
XCTAssertEqualObjects(layer.hillshadeExaggeration, functionExpression,
@"hillshadeExaggeration should round-trip camera expressions.");
-
layer.hillshadeExaggeration = nil;
XCTAssertTrue(rawLayer->getHillshadeExaggeration().isUndefined(),
@@ -159,13 +157,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeHighlightColor(), propertyValue,
@"Setting hillshadeHighlightColor to a camera expression should update hillshade-highlight-color.");
XCTAssertEqualObjects(layer.hillshadeHighlightColor, functionExpression,
@"hillshadeHighlightColor should round-trip camera expressions.");
-
layer.hillshadeHighlightColor = nil;
XCTAssertTrue(rawLayer->getHillshadeHighlightColor().isUndefined(),
@@ -212,13 +209,12 @@
{ 18, mbgl::style::HillshadeIlluminationAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::HillshadeIlluminationAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeIlluminationAnchor(), propertyValue,
@"Setting hillshadeIlluminationAnchor to a camera expression should update hillshade-illumination-anchor.");
XCTAssertEqualObjects(layer.hillshadeIlluminationAnchor, functionExpression,
@"hillshadeIlluminationAnchor should round-trip camera expressions.");
-
layer.hillshadeIlluminationAnchor = nil;
XCTAssertTrue(rawLayer->getHillshadeIlluminationAnchor().isUndefined(),
@@ -256,13 +252,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeIlluminationDirection(), propertyValue,
@"Setting hillshadeIlluminationDirection to a camera expression should update hillshade-illumination-direction.");
XCTAssertEqualObjects(layer.hillshadeIlluminationDirection, functionExpression,
@"hillshadeIlluminationDirection should round-trip camera expressions.");
-
layer.hillshadeIlluminationDirection = nil;
XCTAssertTrue(rawLayer->getHillshadeIlluminationDirection().isUndefined(),
@@ -300,13 +295,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeShadowColor(), propertyValue,
@"Setting hillshadeShadowColor to a camera expression should update hillshade-shadow-color.");
XCTAssertEqualObjects(layer.hillshadeShadowColor, functionExpression,
@"hillshadeShadowColor should round-trip camera expressions.");
-
layer.hillshadeShadowColor = nil;
XCTAssertTrue(rawLayer->getHillshadeShadowColor().isUndefined(),
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 5490278e98..aa24bc8c15 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, mbgl::style::LineCapType::Square },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineCapType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
@"Setting lineCap to a camera expression should update line-cap.");
XCTAssertEqualObjects(layer.lineCap, functionExpression,
@"lineCap should round-trip camera expressions.");
-
layer.lineCap = nil;
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@@ -115,13 +114,12 @@
{ 18, mbgl::style::LineJoinType::Miter },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineJoinType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a camera expression should update line-join.");
XCTAssertEqualObjects(layer.lineJoin, functionExpression,
@"lineJoin should round-trip camera expressions.");
-
layer.lineJoin = nil;
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@@ -153,13 +151,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
@"Setting lineMiterLimit to a camera expression should update line-miter-limit.");
XCTAssertEqualObjects(layer.lineMiterLimit, functionExpression,
@"lineMiterLimit should round-trip camera expressions.");
-
layer.lineMiterLimit = nil;
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@@ -197,13 +194,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
@"Setting lineRoundLimit to a camera expression should update line-round-limit.");
XCTAssertEqualObjects(layer.lineRoundLimit, functionExpression,
@"lineRoundLimit should round-trip camera expressions.");
-
layer.lineRoundLimit = nil;
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@@ -241,7 +237,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
@"Setting lineBlur to a camera expression should update line-blur.");
XCTAssertEqualObjects(layer.lineBlur, functionExpression,
@@ -272,7 +268,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineBlur, pedanticFunctionExpression,
@"lineBlur should round-trip camera-data expressions.");
-
layer.lineBlur = nil;
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@@ -313,7 +308,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
@"Setting lineColor to a camera expression should update line-color.");
XCTAssertEqualObjects(layer.lineColor, functionExpression,
@@ -344,7 +339,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineColor, pedanticFunctionExpression,
@"lineColor should round-trip camera-data expressions.");
-
layer.lineColor = nil;
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@@ -385,13 +379,12 @@
{ 18, {1, 2} },
}};
propertyValue = mbgl::style::CameraFunction<std::vector<float>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
@"Setting lineDashPattern to a camera expression should update line-dasharray.");
XCTAssertEqualObjects(layer.lineDashPattern, functionExpression,
@"lineDashPattern should round-trip camera expressions.");
-
layer.lineDashPattern = nil;
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@@ -429,7 +422,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
@"Setting lineGapWidth to a camera expression should update line-gap-width.");
XCTAssertEqualObjects(layer.lineGapWidth, functionExpression,
@@ -460,7 +453,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineGapWidth, pedanticFunctionExpression,
@"lineGapWidth should round-trip camera-data expressions.");
-
layer.lineGapWidth = nil;
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@@ -501,7 +493,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
@"Setting lineOffset to a camera expression should update line-offset.");
XCTAssertEqualObjects(layer.lineOffset, functionExpression,
@@ -532,7 +524,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineOffset, pedanticFunctionExpression,
@"lineOffset should round-trip camera-data expressions.");
-
layer.lineOffset = nil;
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@@ -573,7 +564,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
@"Setting lineOpacity to a camera expression should update line-opacity.");
XCTAssertEqualObjects(layer.lineOpacity, functionExpression,
@@ -604,7 +595,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineOpacity, pedanticFunctionExpression,
@"lineOpacity should round-trip camera-data expressions.");
-
layer.lineOpacity = nil;
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@@ -645,13 +635,12 @@
{ 18, "Line Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
@"Setting linePattern to a camera expression should update line-pattern.");
XCTAssertEqualObjects(layer.linePattern, functionExpression,
@"linePattern should round-trip camera expressions.");
-
layer.linePattern = nil;
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@@ -704,13 +693,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
@"Setting lineTranslation to a camera expression should update line-translate.");
XCTAssertEqualObjects(layer.lineTranslation, functionExpression,
@"lineTranslation should round-trip camera expressions.");
-
layer.lineTranslation = nil;
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@@ -748,13 +736,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
@"Setting lineTranslationAnchor to a camera expression should update line-translate-anchor.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, functionExpression,
@"lineTranslationAnchor should round-trip camera expressions.");
-
layer.lineTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@@ -792,7 +779,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a camera expression should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, functionExpression,
@@ -823,7 +810,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineWidth, pedanticFunctionExpression,
@"lineWidth should round-trip camera-data expressions.");
-
layer.lineWidth = nil;
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m
index 2a8715d991..a3ee7e3433 100644
--- a/platform/darwin/test/MGLNSStringAdditionsTests.m
+++ b/platform/darwin/test/MGLNSStringAdditionsTests.m
@@ -40,37 +40,29 @@
}
- (void)testTransliteratedString {
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Portland");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Portland");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Портланд");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Arab"], @"پُرتلَند");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Portland");
-
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Latn"], @"běi jīng");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Hans"], @"北京");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"бе̌и йӣнг");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Arab"], @"بِِ̌ جِينگ");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Fake"], @"北京");
-
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Moskva");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Mосква");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Москва");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Arab"], @"مُسكڤَ");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Mосква");
-
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Latn"], @"rondon");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Hans"], @"ロンドン");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"рондон");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Arab"], @"رُندُن");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Fake"], @"ロンドン");
- } else {
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Arab"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Made-up Place");
- }
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Портланд");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Arab"], @"پُرتلَند");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Portland");
+
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Latn"], @"běi jīng");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Hans"], @"北京");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"бе̌и йӣнг");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Arab"], @"بِِ̌ جِينگ");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Fake"], @"北京");
+
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Moskva");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Mосква");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Москва");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Arab"], @"مُسكڤَ");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Mосква");
+
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Latn"], @"rondon");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Hans"], @"ロンドン");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"рондон");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Arab"], @"رُندُن");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Fake"], @"ロンドン");
}
@end
diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm
index 4e7b3e7e4b..41c2d56868 100644
--- a/platform/darwin/test/MGLPredicateTests.mm
+++ b/platform/darwin/test/MGLPredicateTests.mm
@@ -216,64 +216,64 @@
mustRoundTrip:NO];
}
{
- NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
+ NSArray *expected = @[@"match", @[@"id"], @[@6, @5, @4, @3], @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"$featureIdentifier IN { 6, 5, 4, 3}"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST($featureIdentifier, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($featureIdentifier, { 3, 4, 5, 6 }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"!", @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO]];
+ NSArray *expected = @[@"!", @[@"match", @[@"get", @"x"], @[@6, @5, @4, @3], @YES, @NO]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NOT x IN { 6, 5, 4, 3}"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"NOT MGL_MATCH(CAST(x, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"NOT MGL_MATCH(x, { 3, 4, 5, 6 }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"match", @[@"get", @"a"], @"b", @YES, @"c", @YES, @NO];
+ NSArray *expected = @[@"match", @[@"get", @"a"], @[@"b", @"c"], @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"a IN { 'b', 'c' }"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST(a, 'NSString'), 'b', YES, 'c', YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(a, { 'b', 'c' }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"match", @[@"geometry-type"], @"LineString", @YES, @"Polygon", @YES, @NO];
+ NSArray *expected = @[@"match", @[@"geometry-type"], @[@"LineString", @"Polygon"], @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ IN %@", [NSExpression expressionForVariable:@"geometryType"], @[@"LineString", @"Polygon"]];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, 'LineString', YES, 'Polygon', YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, { 'LineString', 'Polygon' }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"match", @[@"get", @"x"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS x"];
+ NSArray *expected = @[@"match", @[@"get", @"x"], @[@6, @5, @4, @3], @YES, @NO];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3 } CONTAINS x"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST(x, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(x, { 3, 4, 5, 6 }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"match", @[@"geometry-type"], @"LineString", @YES, @"Polygon", @YES, @NO];
+ NSArray *expected = @[@"match", @[@"geometry-type"], @[@"LineString", @"Polygon"], @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ CONTAINS %@", @[@"LineString", @"Polygon"], [NSExpression expressionForVariable:@"geometryType"]];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, 'LineString', YES, 'Polygon', YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($geometryType, { 'LineString', 'Polygon' }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
}
{
- NSArray *expected = @[@"match", @[@"id"], @6, @YES, @5, @YES, @4, @YES, @3, @YES, @NO];
+ NSArray *expected = @[@"match", @[@"id"], @[@6, @5, @4, @3], @YES, @NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"{ 6, 5, 4, 3} CONTAINS $featureIdentifier"];
XCTAssertEqualObjects(predicate.mgl_jsonExpressionObject, expected);
- NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH(CAST($featureIdentifier, 'NSNumber'), 3, YES, 4, YES, 5, YES, 6, YES, NO) == YES"];
+ NSPredicate *predicateAfter = [NSPredicate predicateWithFormat:@"MGL_MATCH($featureIdentifier, { 3, 4, 5, 6 }, YES, NO) == YES"];
auto forwardFilter = [NSPredicate predicateWithMGLJSONObject:expected].mgl_filter;
NSPredicate *forwardPredicateAfter = [NSPredicate mgl_predicateWithFilter:forwardFilter];
XCTAssertEqualObjects(predicateAfter, forwardPredicateAfter);
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm
index c8e454743e..cf5175812e 100644
--- a/platform/darwin/test/MGLRasterStyleLayerTests.mm
+++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm
@@ -53,13 +53,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
@"Setting maximumRasterBrightness to a camera expression should update raster-brightness-max.");
XCTAssertEqualObjects(layer.maximumRasterBrightness, functionExpression,
@"maximumRasterBrightness should round-trip camera expressions.");
-
layer.maximumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@@ -97,13 +96,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
@"Setting minimumRasterBrightness to a camera expression should update raster-brightness-min.");
XCTAssertEqualObjects(layer.minimumRasterBrightness, functionExpression,
@"minimumRasterBrightness should round-trip camera expressions.");
-
layer.minimumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@@ -141,13 +139,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
@"Setting rasterContrast to a camera expression should update raster-contrast.");
XCTAssertEqualObjects(layer.rasterContrast, functionExpression,
@"rasterContrast should round-trip camera expressions.");
-
layer.rasterContrast = nil;
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@@ -194,13 +191,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
@"Setting rasterFadeDuration to a camera expression should update raster-fade-duration.");
XCTAssertEqualObjects(layer.rasterFadeDuration, functionExpression,
@"rasterFadeDuration should round-trip camera expressions.");
-
layer.rasterFadeDuration = nil;
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@@ -238,13 +234,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
@"Setting rasterHueRotation to a camera expression should update raster-hue-rotate.");
XCTAssertEqualObjects(layer.rasterHueRotation, functionExpression,
@"rasterHueRotation should round-trip camera expressions.");
-
layer.rasterHueRotation = nil;
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@@ -282,13 +277,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
@"Setting rasterOpacity to a camera expression should update raster-opacity.");
XCTAssertEqualObjects(layer.rasterOpacity, functionExpression,
@"rasterOpacity should round-trip camera expressions.");
-
layer.rasterOpacity = nil;
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@@ -335,13 +329,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
@"Setting rasterSaturation to a camera expression should update raster-saturation.");
XCTAssertEqualObjects(layer.rasterSaturation, functionExpression,
@"rasterSaturation should round-trip camera expressions.");
-
layer.rasterSaturation = nil;
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
diff --git a/platform/darwin/test/MGLStyleLayerTests.h b/platform/darwin/test/MGLStyleLayerTests.h
index 28c316c8ba..c7577819b8 100644
--- a/platform/darwin/test/MGLStyleLayerTests.h
+++ b/platform/darwin/test/MGLStyleLayerTests.h
@@ -14,7 +14,7 @@
@interface NSString (MGLStyleLayerTestAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(NSString *) *lexicalClasses;
+@property (nonatomic, readonly, copy) NSArray<NSString *> *lexicalClasses;
@property (nonatomic, readonly, copy) NSString *lemma;
@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m
index b51fa02af4..52b36dba00 100644
--- a/platform/darwin/test/MGLStyleLayerTests.m
+++ b/platform/darwin/test/MGLStyleLayerTests.m
@@ -33,7 +33,7 @@
}
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean {
- NS_MUTABLE_ARRAY_OF(NSString *) *components = [name componentsSeparatedByString:@"-"].mutableCopy;
+ NSMutableArray<NSString *> *components = [name componentsSeparatedByString:@"-"].mutableCopy;
if (isBoolean) {
if ([components.firstObject isEqualToString:@"is"]) {
[components removeObjectAtIndex:0];
@@ -67,7 +67,7 @@
@implementation NSString (MGLStyleLayerTestAdditions)
-- (NS_ARRAY_OF(NSString *) *)lexicalClasses {
+- (NSArray<NSString *> *)lexicalClasses {
NSOrthography *orthography = [NSOrthography orthographyWithDominantScript:@"Latn"
languageMap:@{@"Latn": @[@"en"]}];
NSLinguisticTaggerOptions options = (NSLinguisticTaggerOmitPunctuation
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
index f70f0bba23..57e5fce533 100644
--- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -59,7 +59,7 @@
MGLTransition transitionTest = MGLTransitionMake(5, 4);
<% for (const property of properties) { -%>
-<% if (property.name === 'heatmap-color') continue; -%>
+<% if (property['property-type'] === 'color-ramp') continue; -%>
// <%- originalPropertyName(property) %>
{
@@ -69,7 +69,7 @@
NSExpression *constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, type, true, 3) %>];
layer.<%- objCName(property) %> = constantExpression;
-<% if (property["property-function"]) { -%>
+<% if (isDataDriven(property)) { -%>
mbgl::style::DataDrivenPropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
@@ -88,13 +88,13 @@
{ 18, <%- mbglTestValue(property, type) %> },
}};
propertyValue = mbgl::style::CameraFunction<<%- mbglType(property) %>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
@"Setting <%- objCName(property) %> to a camera expression should update <%- originalPropertyName(property) %>.");
XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionExpression,
@"<%- objCName(property) %> should round-trip camera expressions.");
-<% if (property["property-function"] && isInterpolatable(property)) { -%>
+<% if (isDataDriven(property) && isInterpolatable(property)) { -%>
functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
layer.<%- objCName(property) %> = functionExpression;
@@ -120,7 +120,7 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.<%- objCName(property) %>, pedanticFunctionExpression,
@"<%- objCName(property) %> should round-trip camera-data expressions.");
-<% } -%>
+<% } -%>
<% if (!property.required) { -%>
layer.<%- objCName(property) %> = nil;
@@ -129,7 +129,7 @@
XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultExpression,
@"<%- objCName(property) %> should return the default value after being unset.");
<% } -%>
-<% if (!property["property-function"]) { -%>
+<% if (!isDataDriven(property)) { -%>
functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionExpression, NSException, NSInvalidArgumentException, @"MGL<%- camelize(type) %>Layer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
@@ -154,7 +154,7 @@
- (void)testPropertyNames {
<% for (const property of properties) { -%>
-<% if (property.name === 'heatmap-color') continue; -%>
+<% if (property['property-type'] === 'color-ramp') continue; -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index cf2f80125a..e1a7ee4e0e 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
@"Setting iconAllowsOverlap to a camera expression should update icon-allow-overlap.");
XCTAssertEqualObjects(layer.iconAllowsOverlap, functionExpression,
@"iconAllowsOverlap should round-trip camera expressions.");
-
layer.iconAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@@ -115,13 +114,12 @@
{ 18, mbgl::style::SymbolAnchorType::BottomRight },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
@"Setting iconAnchor to a camera expression should update icon-anchor.");
XCTAssertEqualObjects(layer.iconAnchor, functionExpression,
@"iconAnchor should round-trip camera expressions.");
-
layer.iconAnchor = nil;
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
@@ -153,13 +151,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
@"Setting iconIgnoresPlacement to a camera expression should update icon-ignore-placement.");
XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionExpression,
@"iconIgnoresPlacement should round-trip camera expressions.");
-
layer.iconIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@@ -197,13 +194,12 @@
{ 18, "Icon Image" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
@"Setting iconImageName to a camera expression should update icon-image.");
XCTAssertEqualObjects(layer.iconImageName, functionExpression,
@"iconImageName should round-trip camera expressions.");
-
layer.iconImageName = nil;
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@@ -241,7 +237,7 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
@"Setting iconOffset to a camera expression should update icon-offset.");
XCTAssertEqualObjects(layer.iconOffset, functionExpression,
@@ -272,7 +268,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconOffset, pedanticFunctionExpression,
@"iconOffset should round-trip camera-data expressions.");
-
layer.iconOffset = nil;
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@@ -304,13 +299,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
@"Setting iconOptional to a camera expression should update icon-optional.");
XCTAssertEqualObjects(layer.iconOptional, functionExpression,
@"iconOptional should round-trip camera expressions.");
-
layer.iconOptional = nil;
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@@ -348,13 +342,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
@"Setting iconPadding to a camera expression should update icon-padding.");
XCTAssertEqualObjects(layer.iconPadding, functionExpression,
@"iconPadding should round-trip camera expressions.");
-
layer.iconPadding = nil;
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@@ -392,13 +385,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
@"Setting iconPitchAlignment to a camera expression should update icon-pitch-alignment.");
XCTAssertEqualObjects(layer.iconPitchAlignment, functionExpression,
@"iconPitchAlignment should round-trip camera expressions.");
-
layer.iconPitchAlignment = nil;
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
@@ -436,7 +428,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
@"Setting iconRotation to a camera expression should update icon-rotate.");
XCTAssertEqualObjects(layer.iconRotation, functionExpression,
@@ -467,7 +459,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconRotation, pedanticFunctionExpression,
@"iconRotation should round-trip camera-data expressions.");
-
layer.iconRotation = nil;
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@@ -499,13 +490,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
@"Setting iconRotationAlignment to a camera expression should update icon-rotation-alignment.");
XCTAssertEqualObjects(layer.iconRotationAlignment, functionExpression,
@"iconRotationAlignment should round-trip camera expressions.");
-
layer.iconRotationAlignment = nil;
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@@ -543,7 +533,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
@"Setting iconScale to a camera expression should update icon-size.");
XCTAssertEqualObjects(layer.iconScale, functionExpression,
@@ -574,7 +564,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconScale, pedanticFunctionExpression,
@"iconScale should round-trip camera-data expressions.");
-
layer.iconScale = nil;
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@@ -606,13 +595,12 @@
{ 18, mbgl::style::IconTextFitType::Both },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::IconTextFitType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
@"Setting iconTextFit to a camera expression should update icon-text-fit.");
XCTAssertEqualObjects(layer.iconTextFit, functionExpression,
@"iconTextFit should round-trip camera expressions.");
-
layer.iconTextFit = nil;
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@@ -656,13 +644,12 @@
{ 18, { 1, 1, 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 4>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
@"Setting iconTextFitPadding to a camera expression should update icon-text-fit-padding.");
XCTAssertEqualObjects(layer.iconTextFitPadding, functionExpression,
@"iconTextFitPadding should round-trip camera expressions.");
-
layer.iconTextFitPadding = nil;
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@@ -700,13 +687,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
@"Setting keepsIconUpright to a camera expression should update icon-keep-upright.");
XCTAssertEqualObjects(layer.keepsIconUpright, functionExpression,
@"keepsIconUpright should round-trip camera expressions.");
-
layer.keepsIconUpright = nil;
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@@ -744,13 +730,12 @@
{ 18, false },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
@"Setting keepsTextUpright to a camera expression should update text-keep-upright.");
XCTAssertEqualObjects(layer.keepsTextUpright, functionExpression,
@"keepsTextUpright should round-trip camera expressions.");
-
layer.keepsTextUpright = nil;
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@@ -788,13 +773,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
@"Setting maximumTextAngle to a camera expression should update text-max-angle.");
XCTAssertEqualObjects(layer.maximumTextAngle, functionExpression,
@"maximumTextAngle should round-trip camera expressions.");
-
layer.maximumTextAngle = nil;
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@@ -832,7 +816,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
@"Setting maximumTextWidth to a camera expression should update text-max-width.");
XCTAssertEqualObjects(layer.maximumTextWidth, functionExpression,
@@ -863,7 +847,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.maximumTextWidth, pedanticFunctionExpression,
@"maximumTextWidth should round-trip camera-data expressions.");
-
layer.maximumTextWidth = nil;
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@@ -895,13 +878,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
@"Setting symbolAvoidsEdges to a camera expression should update symbol-avoid-edges.");
XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionExpression,
@"symbolAvoidsEdges should round-trip camera expressions.");
-
layer.symbolAvoidsEdges = nil;
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@@ -939,13 +921,12 @@
{ 18, mbgl::style::SymbolPlacementType::Line },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolPlacementType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
@"Setting symbolPlacement to a camera expression should update symbol-placement.");
XCTAssertEqualObjects(layer.symbolPlacement, functionExpression,
@"symbolPlacement should round-trip camera expressions.");
-
layer.symbolPlacement = nil;
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@@ -983,13 +964,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
@"Setting symbolSpacing to a camera expression should update symbol-spacing.");
XCTAssertEqualObjects(layer.symbolSpacing, functionExpression,
@"symbolSpacing should round-trip camera expressions.");
-
layer.symbolSpacing = nil;
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@@ -1027,13 +1007,12 @@
{ 18, "Text Field" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
@"Setting text to a camera expression should update text-field.");
XCTAssertEqualObjects(layer.text, functionExpression,
@"text should round-trip camera expressions.");
-
layer.text = nil;
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@@ -1065,13 +1044,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
@"Setting textAllowsOverlap to a camera expression should update text-allow-overlap.");
XCTAssertEqualObjects(layer.textAllowsOverlap, functionExpression,
@"textAllowsOverlap should round-trip camera expressions.");
-
layer.textAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@@ -1109,13 +1087,12 @@
{ 18, mbgl::style::SymbolAnchorType::BottomRight },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
@"Setting textAnchor to a camera expression should update text-anchor.");
XCTAssertEqualObjects(layer.textAnchor, functionExpression,
@"textAnchor should round-trip camera expressions.");
-
layer.textAnchor = nil;
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@@ -1147,13 +1124,12 @@
{ 18, { "Text Font", "Tnof Txet" } },
}};
propertyValue = mbgl::style::CameraFunction<std::vector<std::string>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
@"Setting textFontNames to a camera expression should update text-font.");
XCTAssertEqualObjects(layer.textFontNames, functionExpression,
@"textFontNames should round-trip camera expressions.");
-
layer.textFontNames = nil;
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@@ -1185,7 +1161,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
@"Setting textFontSize to a camera expression should update text-size.");
XCTAssertEqualObjects(layer.textFontSize, functionExpression,
@@ -1216,7 +1192,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textFontSize, pedanticFunctionExpression,
@"textFontSize should round-trip camera-data expressions.");
-
layer.textFontSize = nil;
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@@ -1248,13 +1223,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
@"Setting textIgnoresPlacement to a camera expression should update text-ignore-placement.");
XCTAssertEqualObjects(layer.textIgnoresPlacement, functionExpression,
@"textIgnoresPlacement should round-trip camera expressions.");
-
layer.textIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@@ -1292,13 +1266,12 @@
{ 18, mbgl::style::TextJustifyType::Right },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextJustifyType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
@"Setting textJustification to a camera expression should update text-justify.");
XCTAssertEqualObjects(layer.textJustification, functionExpression,
@"textJustification should round-trip camera expressions.");
-
layer.textJustification = nil;
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@@ -1330,7 +1303,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
@"Setting textLetterSpacing to a camera expression should update text-letter-spacing.");
XCTAssertEqualObjects(layer.textLetterSpacing, functionExpression,
@@ -1361,7 +1334,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textLetterSpacing, pedanticFunctionExpression,
@"textLetterSpacing should round-trip camera-data expressions.");
-
layer.textLetterSpacing = nil;
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@@ -1393,13 +1365,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
@"Setting textLineHeight to a camera expression should update text-line-height.");
XCTAssertEqualObjects(layer.textLineHeight, functionExpression,
@"textLineHeight should round-trip camera expressions.");
-
layer.textLineHeight = nil;
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@@ -1443,7 +1414,7 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
@"Setting textOffset to a camera expression should update text-offset.");
XCTAssertEqualObjects(layer.textOffset, functionExpression,
@@ -1474,7 +1445,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textOffset, pedanticFunctionExpression,
@"textOffset should round-trip camera-data expressions.");
-
layer.textOffset = nil;
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@@ -1506,13 +1476,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
@"Setting textOptional to a camera expression should update text-optional.");
XCTAssertEqualObjects(layer.textOptional, functionExpression,
@"textOptional should round-trip camera expressions.");
-
layer.textOptional = nil;
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@@ -1550,13 +1519,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
@"Setting textPadding to a camera expression should update text-padding.");
XCTAssertEqualObjects(layer.textPadding, functionExpression,
@"textPadding should round-trip camera expressions.");
-
layer.textPadding = nil;
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@@ -1594,13 +1562,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
@"Setting textPitchAlignment to a camera expression should update text-pitch-alignment.");
XCTAssertEqualObjects(layer.textPitchAlignment, functionExpression,
@"textPitchAlignment should round-trip camera expressions.");
-
layer.textPitchAlignment = nil;
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@@ -1638,7 +1605,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
@"Setting textRotation to a camera expression should update text-rotate.");
XCTAssertEqualObjects(layer.textRotation, functionExpression,
@@ -1669,7 +1636,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textRotation, pedanticFunctionExpression,
@"textRotation should round-trip camera-data expressions.");
-
layer.textRotation = nil;
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@@ -1701,13 +1667,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
@"Setting textRotationAlignment to a camera expression should update text-rotation-alignment.");
XCTAssertEqualObjects(layer.textRotationAlignment, functionExpression,
@"textRotationAlignment should round-trip camera expressions.");
-
layer.textRotationAlignment = nil;
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@@ -1745,13 +1710,12 @@
{ 18, mbgl::style::TextTransformType::Lowercase },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextTransformType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
@"Setting textTransform to a camera expression should update text-transform.");
XCTAssertEqualObjects(layer.textTransform, functionExpression,
@"textTransform should round-trip camera expressions.");
-
layer.textTransform = nil;
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@@ -1783,7 +1747,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a camera expression should update icon-color.");
XCTAssertEqualObjects(layer.iconColor, functionExpression,
@@ -1814,7 +1778,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconColor, pedanticFunctionExpression,
@"iconColor should round-trip camera-data expressions.");
-
layer.iconColor = nil;
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@@ -1855,7 +1818,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a camera expression should update icon-halo-blur.");
XCTAssertEqualObjects(layer.iconHaloBlur, functionExpression,
@@ -1886,7 +1849,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloBlur, pedanticFunctionExpression,
@"iconHaloBlur should round-trip camera-data expressions.");
-
layer.iconHaloBlur = nil;
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@@ -1927,7 +1889,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a camera expression should update icon-halo-color.");
XCTAssertEqualObjects(layer.iconHaloColor, functionExpression,
@@ -1958,7 +1920,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloColor, pedanticFunctionExpression,
@"iconHaloColor should round-trip camera-data expressions.");
-
layer.iconHaloColor = nil;
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@@ -1999,7 +1960,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a camera expression should update icon-halo-width.");
XCTAssertEqualObjects(layer.iconHaloWidth, functionExpression,
@@ -2030,7 +1991,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloWidth, pedanticFunctionExpression,
@"iconHaloWidth should round-trip camera-data expressions.");
-
layer.iconHaloWidth = nil;
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@@ -2071,7 +2031,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a camera expression should update icon-opacity.");
XCTAssertEqualObjects(layer.iconOpacity, functionExpression,
@@ -2102,7 +2062,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconOpacity, pedanticFunctionExpression,
@"iconOpacity should round-trip camera-data expressions.");
-
layer.iconOpacity = nil;
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@@ -2149,13 +2108,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
@"Setting iconTranslation to a camera expression should update icon-translate.");
XCTAssertEqualObjects(layer.iconTranslation, functionExpression,
@"iconTranslation should round-trip camera expressions.");
-
layer.iconTranslation = nil;
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@@ -2193,13 +2151,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
@"Setting iconTranslationAnchor to a camera expression should update icon-translate-anchor.");
XCTAssertEqualObjects(layer.iconTranslationAnchor, functionExpression,
@"iconTranslationAnchor should round-trip camera expressions.");
-
layer.iconTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@@ -2237,7 +2194,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a camera expression should update text-color.");
XCTAssertEqualObjects(layer.textColor, functionExpression,
@@ -2268,7 +2225,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textColor, pedanticFunctionExpression,
@"textColor should round-trip camera-data expressions.");
-
layer.textColor = nil;
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@@ -2309,7 +2265,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a camera expression should update text-halo-blur.");
XCTAssertEqualObjects(layer.textHaloBlur, functionExpression,
@@ -2340,7 +2296,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloBlur, pedanticFunctionExpression,
@"textHaloBlur should round-trip camera-data expressions.");
-
layer.textHaloBlur = nil;
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@@ -2381,7 +2336,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a camera expression should update text-halo-color.");
XCTAssertEqualObjects(layer.textHaloColor, functionExpression,
@@ -2412,7 +2367,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloColor, pedanticFunctionExpression,
@"textHaloColor should round-trip camera-data expressions.");
-
layer.textHaloColor = nil;
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@@ -2453,7 +2407,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a camera expression should update text-halo-width.");
XCTAssertEqualObjects(layer.textHaloWidth, functionExpression,
@@ -2484,7 +2438,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloWidth, pedanticFunctionExpression,
@"textHaloWidth should round-trip camera-data expressions.");
-
layer.textHaloWidth = nil;
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@@ -2525,7 +2478,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
@"Setting textOpacity to a camera expression should update text-opacity.");
XCTAssertEqualObjects(layer.textOpacity, functionExpression,
@@ -2556,7 +2509,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textOpacity, pedanticFunctionExpression,
@"textOpacity should round-trip camera-data expressions.");
-
layer.textOpacity = nil;
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@@ -2603,13 +2555,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
@"Setting textTranslation to a camera expression should update text-translate.");
XCTAssertEqualObjects(layer.textTranslation, functionExpression,
@"textTranslation should round-trip camera expressions.");
-
layer.textTranslation = nil;
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@@ -2647,13 +2598,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
@"Setting textTranslationAnchor to a camera expression should update text-translate-anchor.");
XCTAssertEqualObjects(layer.textTranslationAnchor, functionExpression,
@"textTranslationAnchor should round-trip camera expressions.");
-
layer.textTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLTestUtility.h b/platform/darwin/test/MGLTestUtility.h
new file mode 100644
index 0000000000..2e02e4f9de
--- /dev/null
+++ b/platform/darwin/test/MGLTestUtility.h
@@ -0,0 +1,27 @@
+
+/**
+ MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN()
+
+ Include this macro at the top of a "pending" test - one that would normally fail,
+ but you want to include is as a compile-time test or as a reminder.
+
+ This will output the included warning in the test log, which `xcpretty` will detect.
+ This allows such pending tests to be identified in CI logs.
+
+ If you provide `MAPBOX_RUN_PENDING_TESTS` as an environment variable ALL pending
+ tests will run.
+
+ In addition, it's a good idea to append `PENDING` to the test method name, as this
+ will also be picked up by xcpretty. PENDING tests will be distinguished by a `⧖`
+ and `[PENDING]`
+ */
+#define MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN() \
+ /* By default, skip pending tests. Otherwise check environment for MAPBOX_RUN_PENDING_TESTS */ \
+ { \
+ NSString *runPendingTests = [[NSProcessInfo processInfo] environment][@"MAPBOX_RUN_PENDING_TESTS"]; \
+ if (![runPendingTests boolValue]) { \
+ /* The following warning will be picked up by xcpretty */ \
+ printf("warning: '%s' is a pending test - skipping\n", __PRETTY_FUNCTION__); \
+ return; \
+ } \
+ }
diff --git a/platform/default/mbgl/map/map_snapshotter.cpp b/platform/default/mbgl/map/map_snapshotter.cpp
index 9341c23cfd..da3a250e0f 100644
--- a/platform/default/mbgl/map/map_snapshotter.cpp
+++ b/platform/default/mbgl/map/map_snapshotter.cpp
@@ -15,7 +15,7 @@ class MapSnapshotter::Impl {
public:
Impl(FileSource&,
Scheduler&,
- const std::string& styleURL,
+ const std::pair<bool, std::string> style,
const Size&,
const float pixelRatio,
const CameraOptions&,
@@ -43,7 +43,7 @@ private:
MapSnapshotter::Impl::Impl(FileSource& fileSource,
Scheduler& scheduler,
- const std::string& styleURL,
+ const std::pair<bool, std::string> style,
const Size& size,
const float pixelRatio,
const CameraOptions& cameraOptions,
@@ -52,8 +52,11 @@ MapSnapshotter::Impl::Impl(FileSource& fileSource,
: frontend(size, pixelRatio, fileSource, scheduler, programCacheDir)
, map(frontend, MapObserver::nullObserver(), size, pixelRatio, fileSource, scheduler, MapMode::Static) {
- map.getStyle().loadURL(styleURL);
-
+ if (style.first) {
+ map.getStyle().loadJSON(style.second);
+ } else{
+ map.getStyle().loadURL(style.second);
+ }
map.jumpTo(cameraOptions);
// Set region, if specified
@@ -134,13 +137,13 @@ LatLngBounds MapSnapshotter::Impl::getRegion() const {
MapSnapshotter::MapSnapshotter(FileSource& fileSource,
Scheduler& scheduler,
- const std::string& styleURL,
+ const std::pair<bool, std::string> style,
const Size& size,
const float pixelRatio,
const CameraOptions& cameraOptions,
const optional<LatLngBounds> region,
const optional<std::string> programCacheDir)
- : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, scheduler, styleURL, size, pixelRatio, cameraOptions, region, programCacheDir)) {
+ : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, scheduler, style, size, pixelRatio, cameraOptions, region, programCacheDir)) {
}
MapSnapshotter::~MapSnapshotter() = default;
diff --git a/platform/default/mbgl/map/map_snapshotter.hpp b/platform/default/mbgl/map/map_snapshotter.hpp
index 985396e5a3..a71da121c0 100644
--- a/platform/default/mbgl/map/map_snapshotter.hpp
+++ b/platform/default/mbgl/map/map_snapshotter.hpp
@@ -27,7 +27,7 @@ class MapSnapshotter {
public:
MapSnapshotter(FileSource& fileSource,
Scheduler& scheduler,
- const std::string& styleURL,
+ const std::pair<bool, std::string> style,
const Size&,
const float pixelRatio,
const CameraOptions&,
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp
index 7670790be9..598a0b182b 100644
--- a/platform/default/mbgl/storage/offline.cpp
+++ b/platform/default/mbgl/storage/offline.cpp
@@ -43,7 +43,7 @@ uint64_t OfflineTilePyramidRegionDefinition::tileCount(style::SourceType type, u
const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange);
unsigned long result = 0;;
for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) {
- result += util::tileCount(bounds, z, tileSize);
+ result += util::tileCount(bounds, z);
}
return result;
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 65c2097182..2b872ab87b 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -10,11 +10,6 @@
namespace mbgl {
-OfflineDatabase::Statement::~Statement() {
- stmt.reset();
- stmt.clearBindings();
-}
-
OfflineDatabase::OfflineDatabase(std::string path_, uint64_t maximumCacheSize_)
: path(std::move(path_)),
maximumCacheSize(maximumCacheSize_) {
@@ -28,48 +23,62 @@ OfflineDatabase::~OfflineDatabase() {
statements.clear();
db.reset();
} catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
+ Log::Error(Event::Database, (int)ex.code, ex.what());
}
}
-void OfflineDatabase::connect(int flags) {
- db = std::make_unique<mapbox::sqlite::Database>(path.c_str(), flags);
- db->setBusyTimeout(Milliseconds::max());
- db->exec("PRAGMA foreign_keys = ON");
-}
-
void OfflineDatabase::ensureSchema() {
if (path != ":memory:") {
- try {
- connect(mapbox::sqlite::ReadWrite);
-
- switch (userVersion()) {
- case 0: break; // cache-only database; ok to delete
- case 1: break; // cache-only database; ok to delete
- case 2: migrateToVersion3(); // fall through
- case 3: // no-op and fall through
- case 4: migrateToVersion5(); // fall through
- case 5: migrateToVersion6(); // fall through
- case 6: return;
- default: break; // downgrade, delete the database
- }
-
- removeExisting();
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
- } catch (mapbox::sqlite::Exception& ex) {
- if (ex.code != mapbox::sqlite::Exception::Code::CANTOPEN && ex.code != mapbox::sqlite::Exception::Code::NOTADB) {
+ auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWrite);
+ if (result.is<mapbox::sqlite::Exception>()) {
+ const auto& ex = result.get<mapbox::sqlite::Exception>();
+ if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
+ // Corrupted; blow it away.
+ removeExisting();
+ } else if (ex.code == mapbox::sqlite::ResultCode::CantOpen) {
+ // Doesn't exist yet.
+ } else {
Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
- throw;
+ throw ex;
}
-
+ } else {
try {
- if (ex.code == mapbox::sqlite::Exception::Code::NOTADB) {
+ db = std::make_unique<mapbox::sqlite::Database>(std::move(result.get<mapbox::sqlite::Database>()));
+ db->setBusyTimeout(Milliseconds::max());
+ db->exec("PRAGMA foreign_keys = ON");
+
+ switch (userVersion()) {
+ case 0:
+ case 1:
+ // cache-only database; ok to delete
+ removeExisting();
+ break;
+ case 2:
+ migrateToVersion3();
+ // fall through
+ case 3:
+ case 4:
+ migrateToVersion5();
+ // fall through
+ case 5:
+ migrateToVersion6();
+ // fall through
+ case 6:
+ // happy path; we're done
+ return;
+ default:
+ // downgrade, delete the database
+ removeExisting();
+ break;
+ }
+ } catch (const mapbox::sqlite::Exception& ex) {
+ // Unfortunately, SQLITE_NOTADB is not always reported upon opening the database.
+ // Apparently sometimes it is delayed until the first read operation.
+ if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
removeExisting();
+ } else {
+ throw;
}
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
- } catch (...) {
- Log::Error(Event::Database, "Unexpected error creating database: %s", util::toString(std::current_exception()).c_str());
- throw;
}
}
}
@@ -77,9 +86,9 @@ void OfflineDatabase::ensureSchema() {
try {
#include "offline_schema.cpp.include"
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
-
- // If you change the schema you must write a migration from the previous version.
+ db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWrite | mapbox::sqlite::Create));
+ db->setBusyTimeout(Milliseconds::max());
+ db->exec("PRAGMA foreign_keys = ON");
db->exec("PRAGMA auto_vacuum = INCREMENTAL");
db->exec("PRAGMA journal_mode = DELETE");
db->exec("PRAGMA synchronous = FULL");
@@ -92,14 +101,13 @@ void OfflineDatabase::ensureSchema() {
}
int OfflineDatabase::userVersion() {
- auto stmt = db->prepare("PRAGMA user_version");
- stmt.run();
- return stmt.get<int>(0);
+ return static_cast<int>(getPragma<int64_t>("PRAGMA user_version"));
}
void OfflineDatabase::removeExisting() {
Log::Warning(Event::Database, "Removing existing incompatible offline database");
+ statements.clear();
db.reset();
try {
@@ -135,14 +143,12 @@ void OfflineDatabase::migrateToVersion6() {
transaction.commit();
}
-OfflineDatabase::Statement OfflineDatabase::getStatement(const char * sql) {
+mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) {
auto it = statements.find(sql);
-
- if (it != statements.end()) {
- return Statement(*it->second);
+ if (it == statements.end()) {
+ it = statements.emplace(sql, std::make_unique<mapbox::sqlite::Statement>(*db, sql)).first;
}
-
- return Statement(*statements.emplace(sql, std::make_unique<mapbox::sqlite::Statement>(db->prepare(sql))).first->second);
+ return *it->second;
}
optional<Response> OfflineDatabase::get(const Resource& resource) {
@@ -209,41 +215,40 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource,
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resource& resource) {
- // clang-format off
- Statement accessedStmt = getStatement(
- "UPDATE resources SET accessed = ?1 WHERE url = ?2");
- // clang-format on
-
- accessedStmt->bind(1, util::now());
- accessedStmt->bind(2, resource.url);
- accessedStmt->run();
+ // Update accessed timestamp used for LRU eviction.
+ {
+ mapbox::sqlite::Query accessedQuery{ getStatement("UPDATE resources SET accessed = ?1 WHERE url = ?2") };
+ accessedQuery.bind(1, util::now());
+ accessedQuery.bind(2, resource.url);
+ accessedQuery.run();
+ }
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
// 0 1 2 3 4 5
"SELECT etag, expires, must_revalidate, modified, data, compressed "
"FROM resources "
- "WHERE url = ?");
+ "WHERE url = ?") };
// clang-format on
- stmt->bind(1, resource.url);
+ query.bind(1, resource.url);
- if (!stmt->run()) {
+ if (!query.run()) {
return {};
}
Response response;
uint64_t size = 0;
- response.etag = stmt->get<optional<std::string>>(0);
- response.expires = stmt->get<optional<Timestamp>>(1);
- response.mustRevalidate = stmt->get<bool>(2);
- response.modified = stmt->get<optional<Timestamp>>(3);
+ response.etag = query.get<optional<std::string>>(0);
+ response.expires = query.get<optional<Timestamp>>(1);
+ response.mustRevalidate = query.get<bool>(2);
+ response.modified = query.get<optional<Timestamp>>(3);
- optional<std::string> data = stmt->get<optional<std::string>>(4);
+ auto data = query.get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
+ } else if (query.get<bool>(5)) {
response.data = std::make_shared<std::string>(util::decompress(*data));
size = data->length();
} else {
@@ -255,16 +260,13 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou
}
optional<int64_t> OfflineDatabase::hasResource(const Resource& resource) {
- // clang-format off
- Statement stmt = getStatement("SELECT length(data) FROM resources WHERE url = ?");
- // clang-format on
-
- stmt->bind(1, resource.url);
- if (!stmt->run()) {
+ mapbox::sqlite::Query query{ getStatement("SELECT length(data) FROM resources WHERE url = ?") };
+ query.bind(1, resource.url);
+ if (!query.run()) {
return {};
}
- return stmt->get<optional<int64_t>>(0);
+ return query.get<optional<int64_t>>(0);
}
bool OfflineDatabase::putResource(const Resource& resource,
@@ -273,19 +275,19 @@ bool OfflineDatabase::putResource(const Resource& resource,
bool compressed) {
if (response.notModified) {
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query notModifiedQuery{ getStatement(
"UPDATE resources "
"SET accessed = ?1, "
" expires = ?2, "
" must_revalidate = ?3 "
- "WHERE url = ?4 ");
+ "WHERE url = ?4 ") };
// clang-format on
- update->bind(1, util::now());
- update->bind(2, response.expires);
- update->bind(3, response.mustRevalidate);
- update->bind(4, resource.url);
- update->run();
+ notModifiedQuery.bind(1, util::now());
+ notModifiedQuery.bind(2, response.expires);
+ notModifiedQuery.bind(3, response.mustRevalidate);
+ notModifiedQuery.bind(4, resource.url);
+ notModifiedQuery.run();
return false;
}
@@ -296,7 +298,7 @@ bool OfflineDatabase::putResource(const Resource& resource,
mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query updateQuery{ getStatement(
"UPDATE resources "
"SET kind = ?1, "
" etag = ?2, "
@@ -306,81 +308,83 @@ bool OfflineDatabase::putResource(const Resource& resource,
" accessed = ?6, "
" data = ?7, "
" compressed = ?8 "
- "WHERE url = ?9 ");
+ "WHERE url = ?9 ") };
// clang-format on
- update->bind(1, int(resource.kind));
- update->bind(2, response.etag);
- update->bind(3, response.expires);
- update->bind(4, response.mustRevalidate);
- update->bind(5, response.modified);
- update->bind(6, util::now());
- update->bind(9, resource.url);
+ updateQuery.bind(1, int(resource.kind));
+ updateQuery.bind(2, response.etag);
+ updateQuery.bind(3, response.expires);
+ updateQuery.bind(4, response.mustRevalidate);
+ updateQuery.bind(5, response.modified);
+ updateQuery.bind(6, util::now());
+ updateQuery.bind(9, resource.url);
if (response.noContent) {
- update->bind(7, nullptr);
- update->bind(8, false);
+ updateQuery.bind(7, nullptr);
+ updateQuery.bind(8, false);
} else {
- update->bindBlob(7, data.data(), data.size(), false);
- update->bind(8, compressed);
+ updateQuery.bindBlob(7, data.data(), data.size(), false);
+ updateQuery.bind(8, compressed);
}
- update->run();
- if (update->changes() != 0) {
+ updateQuery.run();
+ if (updateQuery.changes() != 0) {
transaction.commit();
return false;
}
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT INTO resources (url, kind, etag, expires, must_revalidate, modified, accessed, data, compressed) "
- "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) ");
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) ") };
// clang-format on
- insert->bind(1, resource.url);
- insert->bind(2, int(resource.kind));
- insert->bind(3, response.etag);
- insert->bind(4, response.expires);
- insert->bind(5, response.mustRevalidate);
- insert->bind(6, response.modified);
- insert->bind(7, util::now());
+ insertQuery.bind(1, resource.url);
+ insertQuery.bind(2, int(resource.kind));
+ insertQuery.bind(3, response.etag);
+ insertQuery.bind(4, response.expires);
+ insertQuery.bind(5, response.mustRevalidate);
+ insertQuery.bind(6, response.modified);
+ insertQuery.bind(7, util::now());
if (response.noContent) {
- insert->bind(8, nullptr);
- insert->bind(9, false);
+ insertQuery.bind(8, nullptr);
+ insertQuery.bind(9, false);
} else {
- insert->bindBlob(8, data.data(), data.size(), false);
- insert->bind(9, compressed);
+ insertQuery.bindBlob(8, data.data(), data.size(), false);
+ insertQuery.bind(9, compressed);
}
- insert->run();
+ insertQuery.run();
transaction.commit();
return true;
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource::TileData& tile) {
- // clang-format off
- Statement accessedStmt = getStatement(
- "UPDATE tiles "
- "SET accessed = ?1 "
- "WHERE url_template = ?2 "
- " AND pixel_ratio = ?3 "
- " AND x = ?4 "
- " AND y = ?5 "
- " AND z = ?6 ");
- // clang-format on
+ {
+ // clang-format off
+ mapbox::sqlite::Query accessedQuery{ getStatement(
+ "UPDATE tiles "
+ "SET accessed = ?1 "
+ "WHERE url_template = ?2 "
+ " AND pixel_ratio = ?3 "
+ " AND x = ?4 "
+ " AND y = ?5 "
+ " AND z = ?6 ") };
+ // clang-format on
- accessedStmt->bind(1, util::now());
- accessedStmt->bind(2, tile.urlTemplate);
- accessedStmt->bind(3, tile.pixelRatio);
- accessedStmt->bind(4, tile.x);
- accessedStmt->bind(5, tile.y);
- accessedStmt->bind(6, tile.z);
- accessedStmt->run();
+ accessedQuery.bind(1, util::now());
+ accessedQuery.bind(2, tile.urlTemplate);
+ accessedQuery.bind(3, tile.pixelRatio);
+ accessedQuery.bind(4, tile.x);
+ accessedQuery.bind(5, tile.y);
+ accessedQuery.bind(6, tile.z);
+ accessedQuery.run();
+ }
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
// 0 1 2, 3, 4, 5
"SELECT etag, expires, must_revalidate, modified, data, compressed "
"FROM tiles "
@@ -388,31 +392,31 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
" AND pixel_ratio = ?2 "
" AND x = ?3 "
" AND y = ?4 "
- " AND z = ?5 ");
+ " AND z = ?5 ") };
// clang-format on
- stmt->bind(1, tile.urlTemplate);
- stmt->bind(2, tile.pixelRatio);
- stmt->bind(3, tile.x);
- stmt->bind(4, tile.y);
- stmt->bind(5, tile.z);
+ query.bind(1, tile.urlTemplate);
+ query.bind(2, tile.pixelRatio);
+ query.bind(3, tile.x);
+ query.bind(4, tile.y);
+ query.bind(5, tile.z);
- if (!stmt->run()) {
+ if (!query.run()) {
return {};
}
Response response;
uint64_t size = 0;
- response.etag = stmt->get<optional<std::string>>(0);
- response.expires = stmt->get<optional<Timestamp>>(1);
- response.mustRevalidate = stmt->get<bool>(2);
- response.modified = stmt->get<optional<Timestamp>>(3);
+ response.etag = query.get<optional<std::string>>(0);
+ response.expires = query.get<optional<Timestamp>>(1);
+ response.mustRevalidate = query.get<bool>(2);
+ response.modified = query.get<optional<Timestamp>>(3);
- optional<std::string> data = stmt->get<optional<std::string>>(4);
+ optional<std::string> data = query.get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
+ } else if (query.get<bool>(5)) {
response.data = std::make_shared<std::string>(util::decompress(*data));
size = data->length();
} else {
@@ -425,27 +429,27 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
optional<int64_t> OfflineDatabase::hasTile(const Resource::TileData& tile) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query size{ getStatement(
"SELECT length(data) "
"FROM tiles "
"WHERE url_template = ?1 "
" AND pixel_ratio = ?2 "
" AND x = ?3 "
" AND y = ?4 "
- " AND z = ?5 ");
+ " AND z = ?5 ") };
// clang-format on
- stmt->bind(1, tile.urlTemplate);
- stmt->bind(2, tile.pixelRatio);
- stmt->bind(3, tile.x);
- stmt->bind(4, tile.y);
- stmt->bind(5, tile.z);
+ size.bind(1, tile.urlTemplate);
+ size.bind(2, tile.pixelRatio);
+ size.bind(3, tile.x);
+ size.bind(4, tile.y);
+ size.bind(5, tile.z);
- if (!stmt->run()) {
+ if (!size.run()) {
return {};
}
- return stmt->get<optional<int64_t>>(0);
+ return size.get<optional<int64_t>>(0);
}
bool OfflineDatabase::putTile(const Resource::TileData& tile,
@@ -454,7 +458,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
bool compressed) {
if (response.notModified) {
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query notModifiedQuery{ getStatement(
"UPDATE tiles "
"SET accessed = ?1, "
" expires = ?2, "
@@ -463,18 +467,18 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND pixel_ratio = ?5 "
" AND x = ?6 "
" AND y = ?7 "
- " AND z = ?8 ");
+ " AND z = ?8 ") };
// clang-format on
- update->bind(1, util::now());
- update->bind(2, response.expires);
- update->bind(3, response.mustRevalidate);
- update->bind(4, tile.urlTemplate);
- update->bind(5, tile.pixelRatio);
- update->bind(6, tile.x);
- update->bind(7, tile.y);
- update->bind(8, tile.z);
- update->run();
+ notModifiedQuery.bind(1, util::now());
+ notModifiedQuery.bind(2, response.expires);
+ notModifiedQuery.bind(3, response.mustRevalidate);
+ notModifiedQuery.bind(4, tile.urlTemplate);
+ notModifiedQuery.bind(5, tile.pixelRatio);
+ notModifiedQuery.bind(6, tile.x);
+ notModifiedQuery.bind(7, tile.y);
+ notModifiedQuery.bind(8, tile.z);
+ notModifiedQuery.run();
return false;
}
@@ -485,7 +489,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query updateQuery{ getStatement(
"UPDATE tiles "
"SET modified = ?1, "
" etag = ?2, "
@@ -498,78 +502,75 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND pixel_ratio = ?9 "
" AND x = ?10 "
" AND y = ?11 "
- " AND z = ?12 ");
+ " AND z = ?12 ") };
// clang-format on
- update->bind(1, response.modified);
- update->bind(2, response.etag);
- update->bind(3, response.expires);
- update->bind(4, response.mustRevalidate);
- update->bind(5, util::now());
- update->bind(8, tile.urlTemplate);
- update->bind(9, tile.pixelRatio);
- update->bind(10, tile.x);
- update->bind(11, tile.y);
- update->bind(12, tile.z);
+ updateQuery.bind(1, response.modified);
+ updateQuery.bind(2, response.etag);
+ updateQuery.bind(3, response.expires);
+ updateQuery.bind(4, response.mustRevalidate);
+ updateQuery.bind(5, util::now());
+ updateQuery.bind(8, tile.urlTemplate);
+ updateQuery.bind(9, tile.pixelRatio);
+ updateQuery.bind(10, tile.x);
+ updateQuery.bind(11, tile.y);
+ updateQuery.bind(12, tile.z);
if (response.noContent) {
- update->bind(6, nullptr);
- update->bind(7, false);
+ updateQuery.bind(6, nullptr);
+ updateQuery.bind(7, false);
} else {
- update->bindBlob(6, data.data(), data.size(), false);
- update->bind(7, compressed);
+ updateQuery.bindBlob(6, data.data(), data.size(), false);
+ updateQuery.bind(7, compressed);
}
- update->run();
- if (update->changes() != 0) {
+ updateQuery.run();
+ if (updateQuery.changes() != 0) {
transaction.commit();
return false;
}
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT INTO tiles (url_template, pixel_ratio, x, y, z, modified, must_revalidate, etag, expires, accessed, data, compressed) "
- "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)");
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)") };
// clang-format on
- insert->bind(1, tile.urlTemplate);
- insert->bind(2, tile.pixelRatio);
- insert->bind(3, tile.x);
- insert->bind(4, tile.y);
- insert->bind(5, tile.z);
- insert->bind(6, response.modified);
- insert->bind(7, response.mustRevalidate);
- insert->bind(8, response.etag);
- insert->bind(9, response.expires);
- insert->bind(10, util::now());
+ insertQuery.bind(1, tile.urlTemplate);
+ insertQuery.bind(2, tile.pixelRatio);
+ insertQuery.bind(3, tile.x);
+ insertQuery.bind(4, tile.y);
+ insertQuery.bind(5, tile.z);
+ insertQuery.bind(6, response.modified);
+ insertQuery.bind(7, response.mustRevalidate);
+ insertQuery.bind(8, response.etag);
+ insertQuery.bind(9, response.expires);
+ insertQuery.bind(10, util::now());
if (response.noContent) {
- insert->bind(11, nullptr);
- insert->bind(12, false);
+ insertQuery.bind(11, nullptr);
+ insertQuery.bind(12, false);
} else {
- insert->bindBlob(11, data.data(), data.size(), false);
- insert->bind(12, compressed);
+ insertQuery.bindBlob(11, data.data(), data.size(), false);
+ insertQuery.bind(12, compressed);
}
- insert->run();
+ insertQuery.run();
transaction.commit();
return true;
}
std::vector<OfflineRegion> OfflineDatabase::listRegions() {
- // clang-format off
- Statement stmt = getStatement(
- "SELECT id, definition, description FROM regions");
- // clang-format on
+ mapbox::sqlite::Query query{ getStatement("SELECT id, definition, description FROM regions") };
std::vector<OfflineRegion> result;
- while (stmt->run()) {
+ while (query.run()) {
result.push_back(OfflineRegion(
- stmt->get<int64_t>(0),
- decodeOfflineRegionDefinition(stmt->get<std::string>(1)),
- stmt->get<std::vector<uint8_t>>(2)));
+ query.get<int64_t>(0),
+ decodeOfflineRegionDefinition(query.get<std::string>(1)),
+ query.get<std::vector<uint8_t>>(2)));
}
return result;
@@ -578,39 +579,37 @@ std::vector<OfflineRegion> OfflineDatabase::listRegions() {
OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"INSERT INTO regions (definition, description) "
- "VALUES (?1, ?2) ");
+ "VALUES (?1, ?2) ") };
// clang-format on
- stmt->bind(1, encodeOfflineRegionDefinition(definition));
- stmt->bindBlob(2, metadata);
- stmt->run();
+ query.bind(1, encodeOfflineRegionDefinition(definition));
+ query.bindBlob(2, metadata);
+ query.run();
- return OfflineRegion(stmt->lastInsertRowId(), definition, metadata);
+ return OfflineRegion(query.lastInsertRowId(), definition, metadata);
}
OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) {
// clang-format off
- Statement stmt = getStatement(
- "UPDATE regions SET description = ?1"
- "WHERE id = ?2");
+ mapbox::sqlite::Query query{ getStatement(
+ "UPDATE regions SET description = ?1 "
+ "WHERE id = ?2") };
// clang-format on
- stmt->bindBlob(1, metadata);
- stmt->bind(2, regionID);
- stmt->run();
+ query.bindBlob(1, metadata);
+ query.bind(2, regionID);
+ query.run();
return metadata;
}
void OfflineDatabase::deleteRegion(OfflineRegion&& region) {
- // clang-format off
- Statement stmt = getStatement(
- "DELETE FROM regions WHERE id = ?");
- // clang-format on
-
- stmt->bind(1, region.getID());
- stmt->run();
+ {
+ mapbox::sqlite::Query query{ getStatement("DELETE FROM regions WHERE id = ?") };
+ query.bind(1, region.getID());
+ query.run();
+ }
evict(0);
db->exec("PRAGMA incremental_vacuum");
@@ -656,7 +655,7 @@ uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& re
bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
if (resource.kind == Resource::Kind::Tile) {
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT OR IGNORE INTO region_tiles (region_id, tile_id) "
"SELECT ?1, tiles.id "
"FROM tiles "
@@ -664,24 +663,24 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND pixel_ratio = ?3 "
" AND x = ?4 "
" AND y = ?5 "
- " AND z = ?6 ");
+ " AND z = ?6 ") };
// clang-format on
const Resource::TileData& tile = *resource.tileData;
- insert->bind(1, regionID);
- insert->bind(2, tile.urlTemplate);
- insert->bind(3, tile.pixelRatio);
- insert->bind(4, tile.x);
- insert->bind(5, tile.y);
- insert->bind(6, tile.z);
- insert->run();
-
- if (insert->changes() == 0) {
+ insertQuery.bind(1, regionID);
+ insertQuery.bind(2, tile.urlTemplate);
+ insertQuery.bind(3, tile.pixelRatio);
+ insertQuery.bind(4, tile.x);
+ insertQuery.bind(5, tile.y);
+ insertQuery.bind(6, tile.z);
+ insertQuery.run();
+
+ if (insertQuery.changes() == 0) {
return false;
}
// clang-format off
- Statement select = getStatement(
+ mapbox::sqlite::Query selectQuery{ getStatement(
"SELECT region_id "
"FROM region_tiles, tiles "
"WHERE region_id != ?1 "
@@ -690,58 +689,54 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND x = ?4 "
" AND y = ?5 "
" AND z = ?6 "
- "LIMIT 1 ");
+ "LIMIT 1 ") };
// clang-format on
- select->bind(1, regionID);
- select->bind(2, tile.urlTemplate);
- select->bind(3, tile.pixelRatio);
- select->bind(4, tile.x);
- select->bind(5, tile.y);
- select->bind(6, tile.z);
- return !select->run();
+ selectQuery.bind(1, regionID);
+ selectQuery.bind(2, tile.urlTemplate);
+ selectQuery.bind(3, tile.pixelRatio);
+ selectQuery.bind(4, tile.x);
+ selectQuery.bind(5, tile.y);
+ selectQuery.bind(6, tile.z);
+ return !selectQuery.run();
} else {
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT OR IGNORE INTO region_resources (region_id, resource_id) "
"SELECT ?1, resources.id "
"FROM resources "
- "WHERE resources.url = ?2 ");
+ "WHERE resources.url = ?2 ") };
// clang-format on
- insert->bind(1, regionID);
- insert->bind(2, resource.url);
- insert->run();
+ insertQuery.bind(1, regionID);
+ insertQuery.bind(2, resource.url);
+ insertQuery.run();
- if (insert->changes() == 0) {
+ if (insertQuery.changes() == 0) {
return false;
}
// clang-format off
- Statement select = getStatement(
+ mapbox::sqlite::Query selectQuery{ getStatement(
"SELECT region_id "
"FROM region_resources, resources "
"WHERE region_id != ?1 "
" AND resources.url = ?2 "
- "LIMIT 1 ");
+ "LIMIT 1 ") };
// clang-format on
- select->bind(1, regionID);
- select->bind(2, resource.url);
- return !select->run();
+ selectQuery.bind(1, regionID);
+ selectQuery.bind(2, resource.url);
+ return !selectQuery.run();
}
}
OfflineRegionDefinition OfflineDatabase::getRegionDefinition(int64_t regionID) {
- // clang-format off
- Statement stmt = getStatement(
- "SELECT definition FROM regions WHERE id = ?1");
- // clang-format on
-
- stmt->bind(1, regionID);
- stmt->run();
+ mapbox::sqlite::Query query{ getStatement("SELECT definition FROM regions WHERE id = ?1") };
+ query.bind(1, regionID);
+ query.run();
- return decodeOfflineRegionDefinition(stmt->get<std::string>(0));
+ return decodeOfflineRegionDefinition(query.get<std::string>(0));
}
OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID) {
@@ -760,35 +755,35 @@ OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID)
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedResourceCountAndSize(int64_t regionID) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_resources, resources "
"WHERE region_id = ?1 "
- "AND resource_id = resources.id ");
+ "AND resource_id = resources.id ") };
// clang-format on
- stmt->bind(1, regionID);
- stmt->run();
- return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
+ query.bind(1, regionID);
+ query.run();
+ return { query.get<int64_t>(0), query.get<int64_t>(1) };
}
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedTileCountAndSize(int64_t regionID) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_tiles, tiles "
"WHERE region_id = ?1 "
- "AND tile_id = tiles.id ");
+ "AND tile_id = tiles.id ") };
// clang-format on
- stmt->bind(1, regionID);
- stmt->run();
- return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
+ query.bind(1, regionID);
+ query.run();
+ return { query.get<int64_t>(0), query.get<int64_t>(1) };
}
template <class T>
-T OfflineDatabase::getPragma(const char * sql) {
- Statement stmt = getStatement(sql);
- stmt->run();
- return stmt->get<T>(0);
+T OfflineDatabase::getPragma(const char* sql) {
+ mapbox::sqlite::Query query{ getStatement(sql) };
+ query.run();
+ return query.get<T>(0);
}
// Remove least-recently used resources and tiles until the used database size,
@@ -813,7 +808,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
// size, and because pages can get fragmented on the database.
while (usedSize() + neededFreeSize + pageSize > maximumCacheSize) {
// clang-format off
- Statement accessedStmt = getStatement(
+ mapbox::sqlite::Query accessedQuery{ getStatement(
"SELECT max(accessed) "
"FROM ( "
" SELECT accessed "
@@ -829,16 +824,16 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" WHERE tile_id IS NULL "
" ORDER BY accessed ASC LIMIT ?1 "
") "
- );
- accessedStmt->bind(1, 50);
+ ) };
+ accessedQuery.bind(1, 50);
// clang-format on
- if (!accessedStmt->run()) {
+ if (!accessedQuery.run()) {
return false;
}
- Timestamp accessed = accessedStmt->get<Timestamp>(0);
+ Timestamp accessed = accessedQuery.get<Timestamp>(0);
// clang-format off
- Statement stmt1 = getStatement(
+ mapbox::sqlite::Query resourceQuery{ getStatement(
"DELETE FROM resources "
"WHERE id IN ( "
" SELECT id FROM resources "
@@ -846,14 +841,14 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" ON resource_id = resources.id "
" WHERE resource_id IS NULL "
" AND accessed <= ?1 "
- ") ");
+ ") ") };
// clang-format on
- stmt1->bind(1, accessed);
- stmt1->run();
- uint64_t changes1 = stmt1->changes();
+ resourceQuery.bind(1, accessed);
+ resourceQuery.run();
+ const uint64_t resourceChanges = resourceQuery.changes();
// clang-format off
- Statement stmt2 = getStatement(
+ mapbox::sqlite::Query tileQuery{ getStatement(
"DELETE FROM tiles "
"WHERE id IN ( "
" SELECT id FROM tiles "
@@ -861,16 +856,16 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" ON tile_id = tiles.id "
" WHERE tile_id IS NULL "
" AND accessed <= ?1 "
- ") ");
+ ") ") };
// clang-format on
- stmt2->bind(1, accessed);
- stmt2->run();
- uint64_t changes2 = stmt2->changes();
+ tileQuery.bind(1, accessed);
+ tileQuery.run();
+ const uint64_t tileChanges = tileQuery.changes();
// The cached value of offlineTileCount does not need to be updated
// here because only non-offline tiles can be removed by eviction.
- if (changes1 == 0 && changes2 == 0) {
+ if (resourceChanges == 0 && tileChanges == 0) {
return false;
}
}
@@ -901,16 +896,16 @@ uint64_t OfflineDatabase::getOfflineMapboxTileCount() {
}
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(DISTINCT id) "
"FROM region_tiles, tiles "
"WHERE tile_id = tiles.id "
- "AND url_template LIKE 'mapbox://%' ");
+ "AND url_template LIKE 'mapbox://%' ") };
// clang-format on
- stmt->run();
+ query.run();
- offlineMapboxTileCount = stmt->get<int64_t>(0);
+ offlineMapboxTileCount = query.get<int64_t>(0);
return *offlineMapboxTileCount;
}
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 91b544a9e0..e0d90a9a15 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -15,6 +15,7 @@ namespace mapbox {
namespace sqlite {
class Database;
class Statement;
+class Query;
} // namespace sqlite
} // namespace mapbox
@@ -58,7 +59,6 @@ public:
uint64_t getOfflineMapboxTileCount();
private:
- void connect(int flags);
int userVersion();
void ensureSchema();
void removeExisting();
@@ -66,20 +66,7 @@ private:
void migrateToVersion5();
void migrateToVersion6();
- class Statement {
- public:
- explicit Statement(mapbox::sqlite::Statement& stmt_) : stmt(stmt_) {}
- Statement(Statement&&) = default;
- Statement(const Statement&) = delete;
- ~Statement();
-
- mapbox::sqlite::Statement* operator->() { return &stmt; };
-
- private:
- mapbox::sqlite::Statement& stmt;
- };
-
- Statement getStatement(const char *);
+ mapbox::sqlite::Statement& getStatement(const char *);
optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&);
optional<int64_t> hasTile(const Resource::TileData&);
@@ -102,8 +89,8 @@ private:
std::pair<int64_t, int64_t> getCompletedTileCountAndSize(int64_t regionID);
const std::string path;
- std::unique_ptr<::mapbox::sqlite::Database> db;
- std::unordered_map<const char *, std::unique_ptr<::mapbox::sqlite::Statement>> statements;
+ std::unique_ptr<mapbox::sqlite::Database> db;
+ std::unordered_map<const char *, const std::unique_ptr<mapbox::sqlite::Statement>> statements;
template <class T>
T getPragma(const char *);
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 2e08354fdf..776adc8f3a 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -14,27 +14,20 @@ namespace sqlite {
class DatabaseImpl {
public:
- DatabaseImpl(const char* filename, int flags)
+ DatabaseImpl(sqlite3* db_)
+ : db(db_)
{
- const int error = sqlite3_open_v2(filename, &db, flags, nullptr);
- if (error != SQLITE_OK) {
- const auto message = sqlite3_errmsg(db);
- db = nullptr;
- throw Exception { error, message };
- }
}
~DatabaseImpl()
{
- if (!db) return;
-
const int error = sqlite3_close(db);
if (error != SQLITE_OK) {
mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error);
}
}
- sqlite3* db = nullptr;
+ sqlite3* db;
};
class StatementImpl {
@@ -69,14 +62,84 @@ public:
template <typename T>
using optional = std::experimental::optional<T>;
+static const char* codeToString(const int err) {
+ switch (err) {
+ case SQLITE_OK: return "SQLITE_OK";
+ case SQLITE_ERROR: return "SQLITE_ERROR";
+ case SQLITE_INTERNAL: return "SQLITE_INTERNAL";
+ case SQLITE_PERM: return "SQLITE_PERM";
+ case SQLITE_ABORT: return "SQLITE_ABORT";
+ case SQLITE_BUSY: return "SQLITE_BUSY";
+ case SQLITE_LOCKED: return "SQLITE_LOCKED";
+ case SQLITE_NOMEM: return "SQLITE_NOMEM";
+ case SQLITE_READONLY: return "SQLITE_READONLY";
+ case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
+ case SQLITE_IOERR: return "SQLITE_IOERR";
+ case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
+ case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND";
+ case SQLITE_FULL: return "SQLITE_FULL";
+ case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
+ case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
+ case SQLITE_EMPTY: return "SQLITE_EMPTY";
+ case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
+ case SQLITE_TOOBIG: return "SQLITE_TOOBIG";
+ case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
+ case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
+ case SQLITE_MISUSE: return "SQLITE_MISUSE";
+ case SQLITE_NOLFS: return "SQLITE_NOLFS";
+ case SQLITE_AUTH: return "SQLITE_AUTH";
+ case SQLITE_FORMAT: return "SQLITE_FORMAT";
+ case SQLITE_RANGE: return "SQLITE_RANGE";
+ case SQLITE_NOTADB: return "SQLITE_NOTADB";
+ case SQLITE_NOTICE: return "SQLITE_NOTICE";
+ case SQLITE_WARNING: return "SQLITE_WARNING";
+ case SQLITE_ROW: return "SQLITE_ROW";
+ case SQLITE_DONE: return "SQLITE_DONE";
+ default: return "<unknown>";
+ }
+}
+
static void errorLogCallback(void *, const int err, const char *msg) {
- if (err == SQLITE_ERROR) {
- mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", msg, err);
- } else if (err == SQLITE_WARNING) {
- mbgl::Log::Warning(mbgl::Event::Database, "%s (Code %i)", msg, err);
- } else {
- mbgl::Log::Info(mbgl::Event::Database, "%s (Code %i)", msg, err);
+ auto severity = mbgl::EventSeverity::Info;
+
+ switch (err) {
+ case SQLITE_ERROR: // Generic error
+ case SQLITE_INTERNAL: // Internal logic error in SQLite
+ case SQLITE_PERM: // Access permission denied
+ case SQLITE_ABORT: // Callback routine requested an abort
+ case SQLITE_BUSY: // The database file is locked
+ case SQLITE_LOCKED: // A table in the database is locked
+ case SQLITE_NOMEM: // A malloc() failed
+ case SQLITE_READONLY: // Attempt to write a readonly database
+ case SQLITE_INTERRUPT: // Operation terminated by sqlite3_interrupt(
+ case SQLITE_IOERR: // Some kind of disk I/O error occurred
+ case SQLITE_CORRUPT: // The database disk image is malformed
+ case SQLITE_NOTFOUND: // Unknown opcode in sqlite3_file_control()
+ case SQLITE_FULL: // Insertion failed because database is full
+ case SQLITE_CANTOPEN: // Unable to open the database file
+ case SQLITE_PROTOCOL: // Database lock protocol error
+ case SQLITE_EMPTY: // Internal use only
+ case SQLITE_SCHEMA: // The database schema changed
+ case SQLITE_TOOBIG: // String or BLOB exceeds size limit
+ case SQLITE_CONSTRAINT: // Abort due to constraint violation
+ case SQLITE_MISMATCH: // Data type mismatch
+ case SQLITE_MISUSE: // Library used incorrectly
+ case SQLITE_NOLFS: // Uses OS features not supported on host
+ case SQLITE_AUTH: // Authorization denied
+ case SQLITE_FORMAT: // Not used
+ case SQLITE_RANGE: // 2nd parameter to sqlite3_bind out of range
+ case SQLITE_NOTADB: // File opened that is not a database file
+ severity = mbgl::EventSeverity::Error;
+ break;
+ case SQLITE_WARNING: // Warnings from sqlite3_log()
+ severity = mbgl::EventSeverity::Warning;
+ break;
+ case SQLITE_NOTICE: // Notifications from sqlite3_log()
+ default:
+ break;
}
+
+ mbgl::Log::Record(severity, mbgl::Event::Database, "%s (%s)", msg, codeToString(err));
}
const static bool sqliteVersionCheck __attribute__((unused)) = []() {
@@ -94,11 +157,29 @@ const static bool sqliteVersionCheck __attribute__((unused)) = []() {
return true;
}();
-Database::Database(const std::string &filename, int flags)
- : impl(std::make_unique<DatabaseImpl>(filename.c_str(), flags))
-{
+mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) {
+ sqlite3* db = nullptr;
+ const int error = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr);
+ if (error != SQLITE_OK) {
+ const auto message = sqlite3_errmsg(db);
+ return Exception { error, message };
+ }
+ return Database(std::make_unique<DatabaseImpl>(db));
}
+Database Database::open(const std::string &filename, int flags) {
+ auto result = tryOpen(filename, flags);
+ if (result.is<Exception>()) {
+ throw result.get<Exception>();
+ } else {
+ return std::move(result.get<Database>());
+ }
+}
+
+Database::Database(std::unique_ptr<DatabaseImpl> impl_)
+ : impl(std::move(impl_))
+{}
+
Database::Database(Database &&other)
: impl(std::move(other.impl)) {}
@@ -131,128 +212,137 @@ void Database::exec(const std::string &sql) {
}
}
-Statement Database::prepare(const char *query) {
- assert(impl);
- return Statement(this, query);
+Statement::Statement(Database& db, const char* sql)
+ : impl(std::make_unique<StatementImpl>(db.impl->db, sql)) {
}
-Statement::Statement(Database *db, const char *sql)
- : impl(std::make_unique<StatementImpl>(db->impl->db, sql))
-{
+Statement::~Statement() {
+#ifndef NDEBUG
+ // Crash if we're destructing this object while we know a Query object references this.
+ assert(!used);
+#endif
}
-Statement::Statement(Statement &&other) {
- *this = std::move(other);
-}
+Query::Query(Statement& stmt_) : stmt(stmt_) {
+ assert(stmt.impl);
-Statement &Statement::operator=(Statement &&other) {
- std::swap(impl, other.impl);
- return *this;
+#ifndef NDEBUG
+ assert(!stmt.used);
+ stmt.used = true;
+#endif
}
-Statement::~Statement() = default;
+Query::~Query() {
+ reset();
+ clearBindings();
-template <> void Statement::bind(int offset, std::nullptr_t) {
- assert(impl);
- impl->check(sqlite3_bind_null(impl->stmt, offset));
+#ifndef NDEBUG
+ stmt.used = false;
+#endif
}
-template <> void Statement::bind(int offset, int8_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, std::nullptr_t) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_null(stmt.impl->stmt, offset));
}
-template <> void Statement::bind(int offset, int16_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int8_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, int32_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int16_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, int64_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int32_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint8_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int64_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint16_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint8_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint32_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint16_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, float value) {
- assert(impl);
- impl->check(sqlite3_bind_double(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint32_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, double value) {
- assert(impl);
- impl->check(sqlite3_bind_double(impl->stmt, offset, value));
+template <> void Query::bind(int offset, float value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, bool value) {
- assert(impl);
- impl->check(sqlite3_bind_int(impl->stmt, offset, value));
+template <> void Query::bind(int offset, double value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, const char *value) {
- assert(impl);
- impl->check(sqlite3_bind_text(impl->stmt, offset, value, -1, SQLITE_STATIC));
+template <> void Query::bind(int offset, bool value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int(stmt.impl->stmt, offset, value));
}
-// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
-// was introduced in SQLite 3.8.7, and we need to support earlier versions:
-// iOS 8.0: 3.7.13
-// iOS 8.2: 3.8.5
-// According to http://stackoverflow.com/questions/14288128/what-version-of-sqlite-does-ios-provide,
-// the first iOS version with 3.8.7+ was 9.0, with 3.8.8.
+template <> void Query::bind(int offset, const char *value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, -1, SQLITE_STATIC));
+}
-void Statement::bind(int offset, const char * value, std::size_t length, bool retain) {
- assert(impl);
+// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
+// were introduced in SQLite 3.8.7, and we need to support earlier versions:
+// Android 11: 3.7
+// Android 21: 3.8
+// Android 24: 3.9
+// Per https://developer.android.com/reference/android/database/sqlite/package-summary.
+// The first iOS version with 3.8.7+ was 9.0, with 3.8.8.
+
+void Query::bind(int offset, const char * value, std::size_t length, bool retain) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- impl->check(sqlite3_bind_text(impl->stmt, offset, value, int(length),
+ stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
-void Statement::bind(int offset, const std::string& value, bool retain) {
+void Query::bind(int offset, const std::string& value, bool retain) {
bind(offset, value.data(), value.size(), retain);
}
-void Statement::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
- assert(impl);
+void Query::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- impl->check(sqlite3_bind_blob(impl->stmt, offset, value, int(length),
+ stmt.impl->check(sqlite3_bind_blob(stmt.impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
-void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
bindBlob(offset, value.data(), value.size(), retain);
}
template <>
-void Statement::bind(
+void Query::bind(
int offset, std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
}
-template <> void Statement::bind(int offset, optional<std::string> value) {
+template <> void Query::bind(int offset, optional<std::string> value) {
if (!value) {
bind(offset, nullptr);
} else {
@@ -261,7 +351,7 @@ template <> void Statement::bind(int offset, optional<std::string> value) {
}
template <>
-void Statement::bind(
+void Query::bind(
int offset,
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> value) {
if (!value) {
@@ -271,86 +361,86 @@ void Statement::bind(
}
}
-bool Statement::run() {
- assert(impl);
- const int err = sqlite3_step(impl->stmt);
- impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(impl->stmt));
- impl->changes = sqlite3_changes(sqlite3_db_handle(impl->stmt));
+bool Query::run() {
+ assert(stmt.impl);
+ const int err = sqlite3_step(stmt.impl->stmt);
+ stmt.impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(stmt.impl->stmt));
+ stmt.impl->changes = sqlite3_changes(sqlite3_db_handle(stmt.impl->stmt));
if (err == SQLITE_DONE) {
return false;
} else if (err == SQLITE_ROW) {
return true;
} else if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(impl->stmt)) };
+ throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt.impl->stmt)) };
} else {
return false;
}
}
-template <> bool Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int(impl->stmt, offset);
+template <> bool Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int(stmt.impl->stmt, offset);
}
-template <> int Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int(impl->stmt, offset);
+template <> int Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int(stmt.impl->stmt, offset);
}
-template <> int64_t Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int64(impl->stmt, offset);
+template <> int64_t Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int64(stmt.impl->stmt, offset);
}
-template <> double Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_double(impl->stmt, offset);
+template <> double Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_double(stmt.impl->stmt, offset);
}
-template <> std::string Statement::get(int offset) {
- assert(impl);
+template <> std::string Query::get(int offset) {
+ assert(stmt.impl);
return {
- reinterpret_cast<const char *>(sqlite3_column_blob(impl->stmt, offset)),
- size_t(sqlite3_column_bytes(impl->stmt, offset))
+ reinterpret_cast<const char *>(sqlite3_column_blob(stmt.impl->stmt, offset)),
+ size_t(sqlite3_column_bytes(stmt.impl->stmt, offset))
};
}
-template <> std::vector<uint8_t> Statement::get(int offset) {
- assert(impl);
- const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
- const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
+template <> std::vector<uint8_t> Query::get(int offset) {
+ assert(stmt.impl);
+ const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt.impl->stmt, offset));
+ const uint8_t* end = begin + sqlite3_column_bytes(stmt.impl->stmt, offset);
return { begin, end };
}
template <>
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
-Statement::get(int offset) {
- assert(impl);
+Query::get(int offset) {
+ assert(stmt.impl);
return std::chrono::time_point_cast<std::chrono::seconds>(
- std::chrono::system_clock::from_time_t(sqlite3_column_int64(impl->stmt, offset)));
+ std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt.impl->stmt, offset)));
}
-template <> optional<int64_t> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<int64_t> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<int64_t>();
} else {
return get<int64_t>(offset);
}
}
-template <> optional<double> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<double> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<double>();
} else {
return get<double>(offset);
}
}
-template <> optional<std::string> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<std::string> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<std::string>();
} else {
return get<std::string>(offset);
@@ -359,9 +449,9 @@ template <> optional<std::string> Statement::get(int offset) {
template <>
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>
-Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return {};
} else {
return get<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>(
@@ -369,24 +459,24 @@ Statement::get(int offset) {
}
}
-void Statement::reset() {
- assert(impl);
- sqlite3_reset(impl->stmt);
+void Query::reset() {
+ assert(stmt.impl);
+ sqlite3_reset(stmt.impl->stmt);
}
-void Statement::clearBindings() {
- assert(impl);
- sqlite3_clear_bindings(impl->stmt);
+void Query::clearBindings() {
+ assert(stmt.impl);
+ sqlite3_clear_bindings(stmt.impl->stmt);
}
-int64_t Statement::lastInsertRowId() const {
- assert(impl);
- return impl->lastInsertRowId;
+int64_t Query::lastInsertRowId() const {
+ assert(stmt.impl);
+ return stmt.impl->lastInsertRowId;
}
-uint64_t Statement::changes() const {
- assert(impl);
- auto changes_ = impl->changes;
+uint64_t Query::changes() const {
+ assert(stmt.impl);
+ auto changes_ = stmt.impl->changes;
return (changes_ < 0 ? 0 : changes_);
}
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 82e3ceff6d..cdc94298fe 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -5,6 +5,7 @@
#include <stdexcept>
#include <chrono>
#include <memory>
+#include <mapbox/variant.hpp>
namespace mapbox {
namespace sqlite {
@@ -19,36 +20,72 @@ enum OpenFlag : int {
PrivateCache = 0x00040000,
};
-struct Exception : std::runtime_error {
- enum Code : int {
- OK = 0,
- CANTOPEN = 14,
- NOTADB = 26
- };
+enum class ResultCode : int {
+ OK = 0,
+ Error = 1,
+ Internal = 2,
+ Perm = 3,
+ Abort = 4,
+ Busy = 5,
+ Locked = 6,
+ NoMem = 7,
+ ReadOnly = 8,
+ Interrupt = 9,
+ IOErr = 10,
+ Corrupt = 11,
+ NotFound = 12,
+ Full = 13,
+ CantOpen = 14,
+ Protocol = 15,
+ Schema = 17,
+ TooBig = 18,
+ Constraint = 19,
+ Mismatch = 20,
+ Misuse = 21,
+ NoLFS = 22,
+ Auth = 23,
+ Range = 25,
+ NotADB = 26
+};
- Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
- Exception(int err, const std::string& msg) : std::runtime_error(msg), code(err) {}
- const int code = OK;
+class Exception : public std::runtime_error {
+public:
+ Exception(int err, const char* msg)
+ : std::runtime_error(msg), code(static_cast<ResultCode>(err)) {
+ }
+ Exception(ResultCode err, const char* msg)
+ : std::runtime_error(msg), code(err) {
+ }
+ Exception(int err, const std::string& msg)
+ : std::runtime_error(msg), code(static_cast<ResultCode>(err)) {
+ }
+ Exception(ResultCode err, const std::string& msg)
+ : std::runtime_error(msg), code(err) {
+ }
+ const ResultCode code = ResultCode::OK;
};
class DatabaseImpl;
class Statement;
class StatementImpl;
+class Query;
class Database {
private:
+ Database(std::unique_ptr<DatabaseImpl>);
Database(const Database &) = delete;
Database &operator=(const Database &) = delete;
public:
- Database(const std::string &filename, int flags = 0);
+ static mapbox::util::variant<Database, Exception> tryOpen(const std::string &filename, int flags = 0);
+ static Database open(const std::string &filename, int flags = 0);
+
Database(Database &&);
~Database();
Database &operator=(Database &&);
void setBusyTimeout(std::chrono::milliseconds);
void exec(const std::string &sql);
- Statement prepare(const char *query);
private:
std::unique_ptr<DatabaseImpl> impl;
@@ -56,28 +93,54 @@ private:
friend class Statement;
};
+// A Statement object represents a prepared statement that can be run repeatedly run with a Query object.
class Statement {
+public:
+ Statement(Database& db, const char* sql);
+ Statement(const Statement&) = delete;
+ Statement(Statement&&) = delete;
+ Statement& operator=(const Statement&) = delete;
+ Statement& operator=(Statement&&) = delete;
+ ~Statement();
+
+ friend class Query;
+
private:
- Statement(const Statement &) = delete;
- Statement &operator=(const Statement &) = delete;
+ std::unique_ptr<StatementImpl> impl;
+
+#ifndef NDEBUG
+ // This flag stores whether there exists a Query object that uses this prepared statement.
+ // There may only be one Query object at a time. Statement objects must outlive Query objects.
+ // While a Query object exists, a Statement object may not be moved or deleted.
+ bool used = false;
+#endif
+};
+// A Query object is used to run a database query with a prepared statement (stored in a Statement
+// object). There may only exist one Query object per Statement object. Query objects are designed
+// to be constructed and destroyed frequently.
+class Query {
public:
- Statement(Database *db, const char *sql);
- Statement(Statement &&);
- ~Statement();
- Statement &operator=(Statement &&);
+ Query(Statement&);
+ Query(const Query&) = delete;
+ Query(Query&&) = delete;
+ Query& operator=(const Query&) = delete;
+ Query& operator=(Query&&) = delete;
+ ~Query();
- template <typename T> void bind(int offset, T value);
+ template <typename T>
+ void bind(int offset, T value);
// Text
- void bind(int offset, const char *, std::size_t length, bool retain = true);
+ void bind(int offset, const char*, std::size_t length, bool retain = true);
void bind(int offset, const std::string&, bool retain = true);
// Blob
- void bindBlob(int offset, const void *, std::size_t length, bool retain = true);
+ void bindBlob(int offset, const void*, std::size_t length, bool retain = true);
void bindBlob(int offset, const std::vector<uint8_t>&, bool retain = true);
- template <typename T> T get(int offset);
+ template <typename T>
+ T get(int offset);
bool run();
void reset();
@@ -87,7 +150,7 @@ public:
uint64_t changes() const;
private:
- std::unique_ptr<StatementImpl> impl;
+ Statement& stmt;
};
class Transaction {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index dfa6708ac6..58495acf7b 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,6 +2,25 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
+## master
+
+### Packaging
+
+* The minimum deployment target for this SDK is now iOS 9.0. ([#11776](https://github.com/mapbox/mapbox-gl-native/pull/11776))
+
+### Style layers
+
+* Added support for aggregate expressions as input values to `MGL_MATCH` expressions. ([#11866](https://github.com/mapbox/mapbox-gl-native/pull/11866))
+
+### Other changes
+
+* Unknown tokens in URLs are now preserved, rather than replaced with an empty string. ([#11787](https://github.com/mapbox/mapbox-gl-native/issues/11787))
+* Adjusted when and how the camera transition update and finish callbacks are called, fixing recursion bugs. ([#11614](https://github.com/mapbox/mapbox-gl-native/pull/11614))
+* Improved application launch performance.
+* Fixed an issue preventing nested key path expressions get parsed accordingly to the spec. ([#11959](https://github.com/mapbox/mapbox-gl-native/pull/11959))
+* Added custom `-hitTest:withEvent:` to `MGLSMCalloutView` to avoid registering taps in transparent areas of the standard annotation callout. ([#11939](https://github.com/mapbox/mapbox-gl-native/pull/11939))
+* Improved performance and memory impact of `MGLScaleBar`. ([#11921](https://github.com/mapbox/mapbox-gl-native/pull/11921))
+
## 4.0.2 - May 29, 2018
* Fixed a crash when constant expressions were used for style properties that didn't support data-driven styling. ([#11960](https://github.com/mapbox/mapbox-gl-native/issues/11960))
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 7a97074d38..34388c2589 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -4,14 +4,10 @@ This document explains how to build the Mapbox Maps SDK for iOS from source. It
## Requirements
-The Mapbox Maps SDK for iOS and iosapp demo application require iOS 8.0 or above. _Note: Support for iOS 8 will be removed in a future release and the minimum iOS deployment version will increase to iOS 9.0._
-
-The Mapbox Maps SDK for iOS requires Xcode 9.1 or above to compile from source.
+See the "Requirements" section in [INSTALL.md](INSTALL.md).
## Building the SDK
-Make sure that you have the [core dependencies](../../INSTALL.md) installed.
-
Create and open an Xcode workspace that includes both the SDK source and some Objective-C test applications by running:
```bash
diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md
index 9c46e7fbe0..bfa7bf7ceb 100644
--- a/platform/ios/INSTALL.md
+++ b/platform/ios/INSTALL.md
@@ -4,13 +4,12 @@ This document explains how to build a development version of Mapbox Maps SDK for
### Requirements
-The Mapbox Maps SDK for iOS is intended to run on iOS 8.0 and above on the following devices:
+The Mapbox Maps SDK for iOS is intended to run on iOS 9.0 and above on the following devices:
* iPhone 4s and above (5, 5c, 5s, 6, 6 Plus, 7, 7 Plus, 8, 8 Plus, X)
* iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2, Pro)
* iPod touch 5th generation and above
-_Note: Support for iOS 8 will be removed in a future release and the minimum iOS deployment version will increase to iOS 9.0._
Note that debugging in 32-bit simulators (such as the iPhone 5 or iPad 2) is only partially supported.
@@ -19,16 +18,34 @@ The Mapbox Maps SDK for iOS requires:
* Xcode 9.1 or higher to compile from source
* Xcode 8.0 or higher to integrate the compiled framework into an application
-### Building the SDK
-
-1. [Install core dependencies](../../INSTALL.md).
+Before building, follow these steps to install prerequisites:
+1. Install [Xcode](https://developer.apple.com/xcode/)
+1. Launch Xcode and install any updates
+1. Install [Homebrew](http://brew.sh)
+1. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org):
+ ```
+ brew install node cmake ccache
+ ```
+1. Install [xcpretty](https://github.com/supermarin/xcpretty) (optional, used for prettifying command line builds):
+ ```
+ [sudo] gem install xcpretty
+ ```
1. Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
```
[sudo] gem install jazzy
```
+### Building the SDK
+
+1. Clone the git repository:
+ ```
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+ ```
+ Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+ but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+ this repository.
1. Run `make iframework BUILDTYPE=Release`. The packaging script will produce a `build/ios/pkg/` folder containing:
- a `dynamic` folder containing a dynamically-linked fat framework with debug symbols for devices and the iOS Simulator
- a `documentation` folder with HTML API documentation
diff --git a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
new file mode 100644
index 0000000000..4a9db60982
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm
@@ -0,0 +1,401 @@
+#import "MGLMapViewIntegrationTest.h"
+#import "MGLTestUtility.h"
+#import "../../darwin/src/MGLGeometry_Private.h"
+
+@interface MBCameraTransitionTests : MGLMapViewIntegrationTest
+@end
+
+@implementation MBCameraTransitionTests
+
+- (void)testSetAndResetNorthWithDispatchAsyncInDelegateMethod {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 2;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ MBCameraTransitionTests *strongSelf = weakself;
+
+ if (!strongSelf) return;
+
+ [expectation fulfill];
+
+ MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading);
+ if (mapView.direction != 0.0) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [mapView resetNorth];
+ });
+ }
+ };
+
+ [self.mapView setDirection:90 animated:YES];
+
+ // loop, render, and wait
+ [self waitForExpectations:@[expectation] timeout:1.5];
+}
+
+
+- (void)testSetAndResetNorthInDelegateMethod {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 2;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ MBCameraTransitionTests *strongSelf = weakself;
+
+ if (!strongSelf) return;
+
+ [expectation fulfill];
+
+ MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading);
+ if (mapView.direction != 0.0) {
+ NSLog(@"Reset to north");
+ [mapView resetNorth];
+ }
+ };
+
+ [self.mapView setDirection:90 animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.5];
+}
+
+- (void)testInterruptingAndResetNorthOnlyOnceInIsChanging {
+
+ // Reset to non-zero, prior to testing
+ [self.mapView setDirection:45 animated:NO];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 1;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+ __block BOOL startedReset = NO;
+ __block BOOL finishedReset = NO;
+
+ self.regionIsChanging = ^(MGLMapView *mapView) {
+ MBCameraTransitionTests *strongSelf = weakself;
+ if (!strongSelf) return;
+
+ if (!startedReset) {
+ NSLog(@"Reset to north, interrupting the previous transition");
+ startedReset = YES;
+ [mapView resetNorth];
+ finishedReset = YES;
+ }
+ };
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+ MBCameraTransitionTests *strongSelf = weakself;
+ if (!strongSelf) return;
+
+ MGLTestAssert(strongSelf, startedReset);
+
+ if (finishedReset) {
+ MGLTestAssert(strongSelf, !(reason & MGLCameraChangeReasonTransitionCancelled));
+ [expectation fulfill];
+ }
+ else {
+ MGLTestAssert(strongSelf, reason & MGLCameraChangeReasonTransitionCancelled);
+ }
+ };
+
+ [self.mapView setDirection:90 animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.5];
+
+ XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001, @"Camera should have reset to north. %0.3f", self.mapView.direction);
+}
+
+- (void)testSetCenterCancelsTransitions {
+ XCTestExpectation *cameraIsInDCExpectation = [self expectationWithDescription:@"camera reset to DC"];
+
+ CLLocationCoordinate2D dc = CLLocationCoordinate2DMake(38.894368, -77.036487);
+ CLLocationCoordinate2D dc_west = CLLocationCoordinate2DMake(38.894368, -77.076487);
+
+ double zoomLevel = 15.0;
+
+ [self.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO];
+ [self.mapView setCenterCoordinate:dc_west zoomLevel:zoomLevel animated:YES];
+
+ __weak typeof(self) weakself = self;
+
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.15 * NSEC_PER_SEC),
+ dispatch_get_main_queue(),
+ ^{
+ MBCameraTransitionTests *strongSelf = weakself;
+
+ [strongSelf.mapView setCenterCoordinate:dc zoomLevel:zoomLevel animated:NO];
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ dc.latitude,
+ strongSelf.mapView.centerCoordinate.latitude,
+ 0.0005,
+ @"setting center coordinate should cancel transitions");
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ dc.longitude,
+ strongSelf.mapView.centerCoordinate.longitude,
+ 0.0005,
+ @"setting center coordinate should cancel transitions");
+ [cameraIsInDCExpectation fulfill];
+ });
+
+ [self waitForExpectations:@[cameraIsInDCExpectation] timeout:10.0];
+}
+
+- (void)testSetCenterCoordinateInDelegateMethod {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 2;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+ __block NSInteger delegateCallCount = 0;
+
+ CLLocationCoordinate2D target = CLLocationCoordinate2DMake(40.0, 40.0);
+ CLLocationCoordinate2D target2 = CLLocationCoordinate2DMake(-40.0, -40.0);
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ MBCameraTransitionTests *strongSelf = weakself;
+
+ if (!strongSelf) return;
+
+ MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading);
+
+ CLLocationCoordinate2D center = mapView.centerCoordinate;
+
+ switch(delegateCallCount) {
+ case 0:
+ {
+ // Our center coordinate should match our target (assuming we're not
+ // constrained by zoom level)
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target.longitude,
+ center.longitude,
+ 0.0005,
+ @"center coordinate longitude should be at target");
+
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target.latitude,
+ center.latitude,
+ 0.0005,
+ @"center coordinate latitude should be at target");
+
+ // Now set another coordinate.
+ // Should take MGLAnimationDuration seconds (0.3s)
+ [mapView setCenterCoordinate:target2 animated:YES];
+ break;
+ }
+
+ case 1:
+ {
+ // Our center coordinate should match our target (assuming we're not
+ // constrained by zoom level)
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target2.longitude,
+ center.longitude,
+ 0.0005,
+ @"center coordinate longitude should be at target2");
+
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target2.latitude,
+ center.latitude,
+ 0.0005,
+ @"center coordinate latitude should be at target2");
+ break;
+
+ }
+
+ default:
+ MGLTestFail(strongSelf);
+ break;
+ }
+
+ delegateCallCount++;
+
+ [expectation fulfill];
+ };
+
+ // Should take MGLAnimationDuration seconds (0.3)
+ [self.mapView setCenterCoordinate:target zoomLevel:15.0 animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.5];
+}
+
+- (void)testFlyToCameraInDelegateMethod {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+
+ __weak typeof(self) weakself = self;
+ __block NSInteger delegateCallCount = 0;
+ expectation.expectedFulfillmentCount = 3;
+ expectation.assertForOverFulfill = YES;
+
+ CLLocationCoordinate2D target = CLLocationCoordinate2DMake(40.0, 40.0);
+ CLLocationCoordinate2D target2 = CLLocationCoordinate2DMake(30.0, 30.0);
+
+ __block BOOL runloop = YES;
+
+ NSTimeInterval stop0 = CACurrentMediaTime();
+ __block NSTimeInterval stop1 = 0.0;
+ __block NSTimeInterval stop2 = 0.0;
+
+ double zoomLevel = 5.0;
+ double altitude = MGLAltitudeForZoomLevel(zoomLevel, 0.0, target.latitude, self.mapView.frame.size);
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ MBCameraTransitionTests *strongSelf = weakself;
+
+ if (!strongSelf) return;
+
+ MGLTestAssert(strongSelf, mapView.userTrackingMode != MGLUserTrackingModeFollowWithHeading);
+
+ CLLocationCoordinate2D center = mapView.centerCoordinate;
+
+ switch(delegateCallCount) {
+ case 0:
+ {
+ stop1 = CACurrentMediaTime();
+
+ // Our center coordinate should match our target (assuming we're not
+ // constrained by zoom level)
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target.longitude,
+ center.longitude,
+ 0.0005,
+ @"center coordinate longitude should be at target");
+
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target.latitude,
+ center.latitude,
+ 0.0005,
+ @"center coordinate latitude should be at target");
+
+ // Now set another coordinate.
+ MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:target2
+ fromDistance:altitude
+ pitch:0.0
+ heading:0.0];
+
+ // flyToCamera can take a while...
+ [mapView flyToCamera:camera completionHandler:^{
+ MGLTestAssert(strongSelf, !runloop, @"Completion block should be called after delegate method");
+ [expectation fulfill];
+ stop2 = CACurrentMediaTime();
+ }];
+ break;
+ }
+
+ case 1:
+ {
+ // Our center coordinate should match our target (assuming we're not
+ // constrained by zoom level)
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target2.longitude,
+ center.longitude,
+ 0.0005,
+ @"center coordinate longitude should be at target2");
+
+ MGLTestAssertEqualWithAccuracy(strongSelf,
+ target2.latitude,
+ center.latitude,
+ 0.0005,
+ @"center coordinate latitude should be at target2");
+
+ runloop = NO;
+ break;
+ }
+
+ default:
+ MGLTestFail(strongSelf);
+ break;
+ }
+
+ delegateCallCount++;
+
+ [expectation fulfill];
+ };
+
+ // Should take MGLAnimationDuration
+ [self.mapView setCenterCoordinate:target zoomLevel:zoomLevel animated:YES];
+
+ // Run the loop, so the camera can fly to the new camera
+ while (runloop) {
+ [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+ }
+ [self waitForExpectations:@[expectation] timeout:0.5];
+
+ NSLog(@"setCenterCoordinate: %0.4fs", stop1 - stop0);
+ NSLog(@"flyToCamera: %0.4fs", stop2 - stop1);
+
+ XCTAssert(delegateCallCount == 2, @"Expecting 2 regionDidChange callbacks, got %ld", delegateCallCount); // Once for the setDirection and once for the reset north
+}
+
+#pragma mark - Pending tests
+
+- (void)testContinuallyResettingNorthInIsChangingPENDING {
+ MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN();
+
+ // See https://github.com/mapbox/mapbox-gl-native/pull/11614
+ // This test currently fails, unsurprisingly, since we're continually
+ // setting the camera to the same parameters during its update.
+ //
+ // Possible solutions/expectations:
+ // - If you set camera parameters that match the *current* target parameters
+ // then the transition could be a no-op. We'd need to consider any completion
+ // block
+ // - Ideally we would detect this case and disallow it.
+
+ // Reset to non-zero, prior to testing
+ [self.mapView setDirection:45 animated:NO];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 2;
+ expectation.assertForOverFulfill = YES;
+
+ self.regionIsChanging = ^(MGLMapView *mapView) {
+ [mapView resetNorth];
+ };
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+ [expectation fulfill];
+ };
+
+ [self.mapView setDirection:90 animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.5];
+
+ XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001, @"Camera should have reset to north. %0.3f", self.mapView.direction);
+}
+
+- (void)testContinuallySettingCoordinateInIsChangingPENDING {
+ // See above comment in `-testContinuallyResettingNorthInIsChangingPENDING`
+ MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN();
+
+ // Reset to non-zero, prior to testing
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(0.0, 0.0) animated:NO];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 2;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+
+ self.regionIsChanging = ^(MGLMapView *mapView) {
+ [weakself.mapView setCenterCoordinate:CLLocationCoordinate2DMake(-40.0, -40.0) animated:YES];
+ };
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+ [expectation fulfill];
+ };
+
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(40.0, 40.0) animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.5];
+
+ XCTAssertEqualWithAccuracy(self.mapView.direction, 0.0, 0.001, @"Camera should have reset to north. %0.3f", self.mapView.direction);
+}
+
+@end
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
index ab5d2cc46f..3ceec8f04a 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
@@ -1,18 +1,24 @@
#import <XCTest/XCTest.h>
#import <Mapbox/Mapbox.h>
+#import "MGLTestUtility.h"
-#define TestFailWithSelf(myself, ...) \
+#define MGLTestFail(myself, ...) \
_XCTPrimitiveFail(myself, __VA_ARGS__)
+#define MGLTestAssert(myself, expression, ...) \
+ _XCTPrimitiveAssertTrue(myself, expression, @#expression, __VA_ARGS__)
+
+#define MGLTestAssertEqualWithAccuracy(myself, expression1, expression2, accuracy, ...) \
+ _XCTPrimitiveAssertEqualWithAccuracy(myself, expression1, @#expression1, expression2, @#expression2, accuracy, @#accuracy, __VA_ARGS__)
+
@interface MGLMapViewIntegrationTest : XCTestCase <MGLMapViewDelegate>
@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) MGLStyle *style;
@property (nonatomic) XCTestExpectation *styleLoadingExpectation;
@property (nonatomic) XCTestExpectation *renderFinishedExpectation;
-@property (nonatomic) void (^regionDidChange)(MGLMapView *mapView, BOOL animated);
+@property (nonatomic) void (^regionWillChange)(MGLMapView *mapView, BOOL animated);
@property (nonatomic) void (^regionIsChanging)(MGLMapView *mapView);
-
-
+@property (nonatomic) void (^regionDidChange)(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated);
// Utility methods
- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout;
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
index fc3229c83b..c42b8eef89 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
@@ -45,9 +45,9 @@
self.renderFinishedExpectation = nil;
}
-- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
- if (self.regionDidChange) {
- self.regionDidChange(mapView, animated);
+- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
+ if (self.regionWillChange) {
+ self.regionWillChange(mapView, animated);
}
}
@@ -57,6 +57,12 @@
}
}
+- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated {
+ if (self.regionDidChange) {
+ self.regionDidChange(mapView, reason, animated);
+ }
+}
+
#pragma mark - Utilities
- (void)waitForMapViewToFinishLoadingStyleWithTimeout:(NSTimeInterval)timeout {
diff --git a/platform/ios/Integration Tests/MGLShapeSourceTests.m b/platform/ios/Integration Tests/MGLShapeSourceTests.m
new file mode 100644
index 0000000000..088a9b011e
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLShapeSourceTests.m
@@ -0,0 +1,126 @@
+//
+// MBShapeSourceTests.m
+// integration
+//
+// Created by Julian Rex on 4/5/18.
+// Copyright © 2018 Mapbox. All rights reserved.
+//
+
+#import "MGLMapViewIntegrationTest.h"
+
+@interface MGLShapeSourceTests : MGLMapViewIntegrationTest
+@end
+
+@implementation MGLShapeSourceTests
+
+- (void)testSettingShapeSourceToNilInRegionDidChange {
+
+ NSMutableArray *features = [[NSMutableArray alloc] init];
+
+ for (NSUInteger i = 0; i <= 180; i+=5) {
+ CLLocationCoordinate2D coord[4] = {
+ CLLocationCoordinate2DMake(round(0), round(i)),
+ CLLocationCoordinate2DMake(round(20), round(i)),
+ CLLocationCoordinate2DMake(round(0), round(i / 2 )),
+ CLLocationCoordinate2DMake(round(20), round(i / 2))};
+
+ MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:coord count:4];
+ [features addObject:feature];
+ }
+
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"source" features:features options:nil];
+ [self.style addSource:shapeSource];
+
+ MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layer" source:shapeSource];
+ layer.fillOpacity = [NSExpression expressionForConstantValue:@0.5];
+ [self.style addLayer:layer];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 1;
+ expectation.assertForOverFulfill = YES;
+
+ __weak typeof(self) weakself = self;
+ __block NSInteger delegateCallCount = 0;
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ MGLShapeSourceTests *strongSelf = weakself;
+
+ if (!strongSelf)
+ return;
+
+ delegateCallCount++;
+
+ // Setting the shapeSource.shape = nil, was causing an infinite loop, so here
+ // we check for a runaway call. 10 here is arbitrary. We could argue that this
+ // should check that the call count is only 1, however in this case we particularly
+ // want to check for the infinite loop.
+ // See https://github.com/mapbox/mapbox-gl-native/issues/11180
+
+ if (delegateCallCount > 10) {
+ MGLTestFail(strongSelf);
+ }
+ else {
+ shapeSource.shape = nil;
+ }
+
+ [expectation fulfill];
+ };
+
+ // setCenterCoordinate is NOT animated here.
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)];
+ [self waitForExpectations:@[expectation] timeout:5.0];
+}
+
+- (void)testSettingShapeSourceToNilInRegionIsChanging {
+
+ NSMutableArray *features = [[NSMutableArray alloc] init];
+
+ for (NSUInteger i = 0; i <= 180; i+=5) {
+ CLLocationCoordinate2D coord[4] = {
+ CLLocationCoordinate2DMake(round(0), round(i)),
+ CLLocationCoordinate2DMake(round(20), round(i)),
+ CLLocationCoordinate2DMake(round(0), round(i / 2 )),
+ CLLocationCoordinate2DMake(round(20), round(i / 2))};
+
+ MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:coord count:4];
+ [features addObject:feature];
+ }
+
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"source" features:features options:nil];
+ [self.style addSource:shapeSource];
+
+ MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layer" source:shapeSource];
+ layer.fillOpacity = [NSExpression expressionForConstantValue:@0.5];
+ [self.style addLayer:layer];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"regionDidChange expectation"];
+ expectation.expectedFulfillmentCount = 1;
+ expectation.assertForOverFulfill = YES;
+
+ __block NSInteger delegateCallCount = 0;
+ __weak typeof(self) weakself = self;
+
+ self.regionIsChanging = ^(MGLMapView *mapView) {
+ // See https://github.com/mapbox/mapbox-gl-native/issues/11180
+ shapeSource.shape = nil;
+ };
+
+ self.regionDidChange = ^(MGLMapView *mapView, MGLCameraChangeReason reason, BOOL animated) {
+
+ delegateCallCount++;
+
+ if (delegateCallCount > 1) {
+ MGLTestFail(weakself);
+ }
+
+ [expectation fulfill];
+ };
+
+ // Should take MGLAnimationDuration seconds (0.3)
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0) animated:YES];
+ [self waitForExpectations:@[expectation] timeout:1.0];
+}
+
+
+@end
diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
index 6c3c593edd..f2d8cee025 100644
--- a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '4.0.2'
+ version = '4.1.0-alpha.1'
m.name = 'Mapbox-iOS-SDK-nightly-dynamic'
m.version = "#{version}-nightly"
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK-static-part.podspec b/platform/ios/Mapbox-iOS-SDK-static-part.podspec
index b2a114f9d2..bd98bb7272 100644
--- a/platform/ios/Mapbox-iOS-SDK-static-part.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-static-part.podspec
@@ -1,4 +1,4 @@
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index d8365fe92c..7f4f27301e 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '4.0.2'
+ version = '4.1.0-alpha.1'
m.name = 'Mapbox-iOS-SDK-symbols'
m.version = "#{version}-symbols"
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 6509c4ea8b..79229c5e8e 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '4.0.2'
+ version = '4.1.0-alpha.1'
m.name = 'Mapbox-iOS-SDK'
m.version = version
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/app/MBXOfflinePacksTableViewController.m b/platform/ios/app/MBXOfflinePacksTableViewController.m
index 26a15a0b95..959ae57548 100644
--- a/platform/ios/app/MBXOfflinePacksTableViewController.m
+++ b/platform/ios/app/MBXOfflinePacksTableViewController.m
@@ -45,7 +45,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"packs"]) {
NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
@@ -119,9 +119,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
}];
}];
[alertController addAction:downloadAction];
- if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
- alertController.preferredAction = downloadAction;
- }
+ alertController.preferredAction = downloadAction;
[self presentViewController:alertController animated:YES completion:nil];
}
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index c3585fbeae..a1479b4538 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -91,6 +91,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) {
typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousShowReuseQueueStats = 0,
MBXSettingsMiscellaneousWorldTour,
+ MBXSettingsMiscellaneousRandomTour,
MBXSettingsMiscellaneousShowZoomLevel,
MBXSettingsMiscellaneousScrollView,
MBXSettingsMiscellaneousToggleTwoMaps,
@@ -101,6 +102,65 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousDeleteLogFile,
};
+// Utility methods
+CLLocationCoordinate2D coordinateCentered(CLLocationCoordinate2D origin, CLLocationDegrees bearing, CLLocationDistance distance) {
+
+ // Convert to radians
+ double multiplier = M_PI / 180.0;
+ double sourceLatitude = multiplier * origin.latitude;
+ double sourceLongitude = multiplier * origin.longitude;
+ bearing *= multiplier;
+ distance /= 6378137.0;
+
+ // Pulled from MGLRadianCoordinateAtDistanceFacingDirection:
+ double latitude = asin((sin(sourceLatitude) * cos(distance)) +
+ (cos(sourceLatitude) * sin(distance) * cos(bearing)));
+
+ double longitude = sourceLongitude + atan2((sin(bearing) * sin(distance) * cos(sourceLatitude)),
+ cos(distance) - (sin(sourceLatitude) * sin(latitude)));
+
+ CLLocationCoordinate2D result;
+ result.latitude = fmin(85.0, fmax(-85.0, (latitude / multiplier)));
+ result.longitude = longitude / multiplier;
+ return result;
+}
+
+CLLocationCoordinate2D randomWorldCoordinate() {
+
+ static const struct {
+ CLLocationCoordinate2D coordinate;
+ CLLocationDistance radius;
+ } landmasses[] = {
+ // Rough land masses
+ {{ 38.328531, 94.778736 }, 4100000 }, // Asia
+ {{ 1.477244, 18.138111 }, 4100000 }, // Africa
+ {{ 52.310059, 22.295425 }, 2000000 }, // Europe
+ {{ 42.344216, -96.532700 }, 3000000 }, // N America
+ {{ -11.537273, -57.035181 }, 2220000 }, // S America
+ {{ -20.997030, 134.660541 }, 2220000 }, // Australia
+
+ // A few cities
+ {{ 51.504787, -0.106977 }, 33000 }, // London
+ {{ 37.740186, -122.437086 }, 8500 }, // SF
+ {{ 52.509978, 13.406510 }, 12000 }, // Berlin
+ {{ 12.966246, 77.586505 }, 19000 } // Bengaluru
+ };
+
+ NSInteger index = drand48() * (sizeof(landmasses)/sizeof(landmasses[0]));
+ CLLocationCoordinate2D coordinate = landmasses[index].coordinate;
+ CLLocationDistance radius = landmasses[index].radius;
+
+ // Now create a world coord
+ CLLocationDegrees heading = drand48()*360.0;
+ CLLocationDistance distance = drand48()*radius;
+ CLLocationCoordinate2D newLocation = coordinateCentered(coordinate, heading, distance);
+ return newLocation;
+}
+
+
+
+
+
@interface MBXDroppedPinAnnotation : MGLPointAnnotation
@end
@@ -136,13 +196,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@property (nonatomic) BOOL reuseQueueStatsEnabled;
@property (nonatomic) BOOL showZoomLevelEnabled;
@property (nonatomic) BOOL shouldLimitCameraChanges;
-
+@property (nonatomic) BOOL randomWalk;
@end
@interface MGLMapView (MBXViewController)
-
@property (nonatomic) NSDictionary *annotationViewReuseQueueByIdentifier;
-
@end
@implementation MBXViewController
@@ -177,9 +235,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
self.mapView.showsScale = YES;
self.mapView.showsUserHeadingIndicator = YES;
- if ([UIFont respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) {
- self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
- }
+ self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
if ([MGLAccountManager accessToken].length)
{
@@ -209,11 +265,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView reloadStyle:self];
}];
[alertController addAction:OKAction];
+ alertController.preferredAction = OKAction;
- if ([alertController respondsToSelector:@selector(setPreferredAction:)])
- {
- alertController.preferredAction = OKAction;
- }
[self presentViewController:alertController animated:YES completion:nil];
}
}
@@ -282,6 +335,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (IBAction)showSettings:(__unused id)sender
{
+ self.randomWalk = NO;
+
UITableViewController *settingsViewController = [[UITableViewController alloc] initWithStyle:UITableViewStyleGrouped];
settingsViewController.tableView.delegate = self;
settingsViewController.tableView.dataSource = self;
@@ -382,6 +437,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[settingsTitles addObjectsFromArray:@[
[NSString stringWithFormat:@"%@ Reuse Queue Stats", (_reuseQueueStatsEnabled ? @"Hide" :@"Show")],
@"Start World Tour",
+ @"Random Tour",
[NSString stringWithFormat:@"%@ Zoom/Pitch/Direction Label", (_showZoomLevelEnabled ? @"Hide" :@"Show")],
@"Embedded Map View",
[NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")],
@@ -585,6 +641,10 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsMiscellaneousWorldTour:
[self startWorldTour];
break;
+ case MBXSettingsMiscellaneousRandomTour:
+ [self randomWorldTour];
+ break;
+
case MBXSettingsMiscellaneousPrintLogFile:
[self printTelemetryLogFile];
break;
@@ -1544,7 +1604,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self continueWorldTourWithRemainingAnnotations:annotations];
}
-- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations
+- (void)continueWorldTourWithRemainingAnnotations:(NSMutableArray<MGLPointAnnotation *> *)annotations
{
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld)
@@ -1686,6 +1746,75 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
return filePath;
}
+#pragma mark - Random World Tour
+
+- (void)addAnnotations:(NSInteger)numAnnotations aroundCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius {
+ NSMutableArray *annotations = [[NSMutableArray alloc] initWithCapacity:numAnnotations];
+ for (NSInteger i = 0; i<numAnnotations; i++) {
+
+ CLLocationDegrees heading = drand48()*360.0;
+ CLLocationDistance distance = drand48()*radius;
+ CLLocationCoordinate2D newLocation = coordinateCentered(coordinate, heading, distance);
+
+ MBXDroppedPinAnnotation *annotation = [[MBXDroppedPinAnnotation alloc] init];
+ annotation.coordinate = newLocation;
+ [annotations addObject:annotation];
+ }
+ [self.mapView addAnnotations:annotations];
+}
+
+- (void)randomWorldTour {
+ // Consistent initial conditions (consider setting these by test params)
+ srand48(0);
+ [self.mapView removeAnnotations:self.mapView.annotations];
+ [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(31, -100) zoomLevel:3 animated:NO];
+
+ [self randomWorldTourInternal];
+}
+
+- (void)randomWorldTourInternal {
+
+ self.randomWalk = YES;
+
+ // Remove all annotations
+ NSTimeInterval duration = 16.0;
+ __weak MBXViewController *weakSelf = self;
+
+ // Remove old annotations, half-way through the flight.
+ NSArray *annotationsToRemove = [self.mapView.annotations copy];
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * 0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ [weakSelf.mapView removeAnnotations:annotationsToRemove];
+ });
+
+ MBXDroppedPinAnnotation *annotation = [[MBXDroppedPinAnnotation alloc] init];
+ annotation.coordinate = randomWorldCoordinate();
+ [self.mapView addAnnotation:annotation];
+
+ // Add annotations around that coord
+ [self addAnnotations:50 aroundCoordinate:annotation.coordinate radius:100000.0]; // 100km
+
+ MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:annotation.coordinate
+ fromDistance:10000.0
+ pitch:drand48()*60.0
+ heading:drand48()*360];
+ [self.mapView flyToCamera:camera
+ withDuration:duration
+ peakAltitude:2000000.0
+ completionHandler:^{
+ // This completion handler is currently called BEFORE the
+ // region did change delegate method, and we don't have a "reason"
+ // so we can't tell if the motion was cancelled. We use the delegate
+ // for that, and set self.randomWalk. But since we want a delay
+ // anyway, we can just check later. Not ideal though..
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ MBXViewController *strongSelf = weakSelf;
+ if (strongSelf.randomWalk) {
+ [strongSelf randomWorldTourInternal];
+ }
+ });
+ }];
+}
+
#pragma mark - User Actions
- (IBAction)handleLongPress:(UILongPressGestureRecognizer *)longPress
@@ -2038,6 +2167,10 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated
{
+ if (reason != MGLCameraChangeReasonProgrammatic) {
+ self.randomWalk = NO;
+ }
+
[self updateHUD];
}
diff --git a/platform/ios/benchmark/MBXBenchViewController.mm b/platform/ios/benchmark/MBXBenchViewController.mm
index d4629e2521..84c2790d50 100644
--- a/platform/ios/benchmark/MBXBenchViewController.mm
+++ b/platform/ios/benchmark/MBXBenchViewController.mm
@@ -76,10 +76,8 @@
[self startBenchmarkIteration];
}];
[alertController addAction:OKAction];
+ alertController.preferredAction = OKAction;
- if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
- alertController.preferredAction = OKAction;
- }
[self presentViewController:alertController animated:YES completion:nil];
}
}
diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index 7cd0376d07..3a95aa96de 100644
--- a/platform/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/)
-The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 8.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 9.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
![Mapbox Maps SDK for iOS screenshots](img/screenshot.png)
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index f94073bd9f..8a3080055d 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/)
-The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 8.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 9.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
For more information, check out the [Mapbox Maps SDK for iOS homepage](https://www.mapbox.com/ios-sdk/) and the [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/CHANGELOG.md) online.
@@ -10,7 +10,7 @@ For more information, check out the [Mapbox Maps SDK for iOS homepage](https://w
The Mapbox Maps SDK for iOS may be installed as either a dynamic framework or a static framework. (To reduce the download size, the static framework is omitted from some distributions; you may need to download the full package from the [release page](https://github.com/mapbox/mapbox-gl-native/releases/).)
-Integrating the Mapbox Maps SDK for iOS requires Xcode 8.0 or higher. To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
+Integrating the Mapbox Maps SDK for iOS requires Xcode 8.0 or higher.
{{DYNAMIC}}
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 46c10dab89..c0909344f3 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -363,8 +363,10 @@
AC518E00201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */; };
AC518E03201BB56000EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
AC518E04201BB56100EBC820 /* MGLTelemetryConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */; };
+ CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */; };
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */; };
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */; };
+ CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */; };
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CAA69DA4206DCD0E007279CD /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA4A26961CB6E795000B7809 /* Mapbox.framework */; };
@@ -996,10 +998,13 @@
96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = "<group>"; };
AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTelemetryConfig.h; sourceTree = "<group>"; };
AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTelemetryConfig.m; sourceTree = "<group>"; };
+ CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLShapeSourceTests.m; sourceTree = "<group>"; };
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewIntegrationTest.m; sourceTree = "<group>"; };
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLMapViewIntegrationTest.h; sourceTree = "<group>"; };
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerIntegrationTests.m; sourceTree = "<group>"; };
+ CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCameraTransitionTests.mm; sourceTree = "<group>"; };
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; };
+ CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestUtility.h; path = ../../darwin/test/MGLTestUtility.h; sourceTree = "<group>"; };
DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
@@ -1353,6 +1358,8 @@
children = (
16376B091FFD9DAF0000563E /* MBGLIntegrationTests.m */,
16376B0B1FFD9DAF0000563E /* Info.plist */,
+ CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */,
+ CA0C27912076C804001CE5B7 /* MGLShapeSourceTests.m */,
CA0C27932076CA19001CE5B7 /* MGLMapViewIntegrationTest.m */,
CA0C27952076CA50001CE5B7 /* MGLMapViewIntegrationTest.h */,
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */,
@@ -1529,6 +1536,7 @@
4031ACFD1E9FD26900A3EA26 /* Test Helpers */ = {
isa = PBXGroup;
children = (
+ CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */,
4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
);
name = "Test Helpers";
@@ -2809,8 +2817,10 @@
buildActionMask = 2147483647;
files = (
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */,
+ CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */,
16376B0A1FFD9DAF0000563E /* MBGLIntegrationTests.m in Sources */,
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
+ CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3379,6 +3389,7 @@
/* Begin XCBuildConfiguration section */
16376B0E1FFD9DAF0000563E /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -3393,8 +3404,8 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = "Integration Tests/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3405,6 +3416,7 @@
};
16376B0F1FFD9DAF0000563E /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
@@ -3419,8 +3431,8 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
+ HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = "Integration Tests/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3446,7 +3458,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Test Harness/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.Integration-Test-Harness";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3471,7 +3482,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Test Harness/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.Integration-Test-Harness";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3531,7 +3541,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -3586,7 +3596,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -3602,7 +3612,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
@@ -3616,7 +3625,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
@@ -3651,7 +3659,6 @@
CLANG_ENABLE_MODULES = YES;
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3676,7 +3683,6 @@
CLANG_ENABLE_MODULES = YES;
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3711,7 +3717,6 @@
);
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3754,7 +3759,6 @@
);
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3868,7 +3872,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/benchmark/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.bench;
PRODUCT_NAME = "Bench GL";
@@ -3880,7 +3883,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/benchmark/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.bench;
PRODUCT_NAME = "Bench GL";
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
index 01b565d5d9..6b018e1337 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
@@ -54,7 +54,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "NO">
<Testables>
<TestableReference
skipped = "NO">
@@ -65,14 +65,6 @@
BlueprintName = "test"
ReferencedContainer = "container:ios.xcodeproj">
</BuildableReference>
- <SkippedTests>
- <Test
- Identifier = "MGLAnnotationViewTests/testAnnotationViewInitWithFrame">
- </Test>
- <Test
- Identifier = "MGLAnnotationViewTests/testSelectingADisabledAnnotationView">
- </Test>
- </SkippedTests>
</TestableReference>
</Testables>
<MacroExpansion>
@@ -84,6 +76,13 @@
ReferencedContainer = "container:ios.xcodeproj">
</BuildableReference>
</MacroExpansion>
+ <EnvironmentVariables>
+ <EnvironmentVariable
+ key = "MAPBOX_RUN_PENDING_TESTS"
+ value = "YES"
+ isEnabled = "NO">
+ </EnvironmentVariable>
+ </EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/Integration Test Harness.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/Integration Test Harness.xcscheme
index 1638592557..ce264aa19a 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/Integration Test Harness.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/Integration Test Harness.xcscheme
@@ -26,7 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
+ shouldUseLaunchSchemeArgsEnv = "NO">
<Testables>
<TestableReference
skipped = "NO">
diff --git a/platform/ios/ios.xcworkspace/contents.xcworkspacedata b/platform/ios/ios.xcworkspace/contents.xcworkspacedata
index 65d928a67d..92247c14f1 100644
--- a/platform/ios/ios.xcworkspace/contents.xcworkspacedata
+++ b/platform/ios/ios.xcworkspace/contents.xcworkspacedata
@@ -5,15 +5,6 @@
location = "group:ios.xcodeproj">
</FileRef>
<FileRef
- location = "group:uitest/ios-tests.xcodeproj">
- </FileRef>
- <FileRef
- location = "group:uitest/KIF/KIF.xcodeproj">
- </FileRef>
- <FileRef
- location = "group:uitest/OHHTTPStubs/OHHTTPStubs/OHHTTPStubs.xcodeproj">
- </FileRef>
- <FileRef
location = "group:../../build/ios/mbgl.xcodeproj">
</FileRef>
</Workspace>
diff --git a/platform/ios/src/MGLAnnotationContainerView.h b/platform/ios/src/MGLAnnotationContainerView.h
index 90d2964831..ccec3052a6 100644
--- a/platform/ios/src/MGLAnnotationContainerView.h
+++ b/platform/ios/src/MGLAnnotationContainerView.h
@@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)annotationContainerViewWithAnnotationContainerView:(MGLAnnotationContainerView *)annotationContainerView;
-- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews;
+- (void)addSubviews:(NSArray<MGLAnnotationView *> *)subviews;
@end
diff --git a/platform/ios/src/MGLAnnotationContainerView.m b/platform/ios/src/MGLAnnotationContainerView.m
index 9a823c839c..6c82a1836d 100644
--- a/platform/ios/src/MGLAnnotationContainerView.m
+++ b/platform/ios/src/MGLAnnotationContainerView.m
@@ -3,7 +3,7 @@
@interface MGLAnnotationContainerView ()
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *annotationViews;
+@property (nonatomic) NSMutableArray<MGLAnnotationView *> *annotationViews;
@end
@@ -26,7 +26,7 @@
return newAnnotationContainerView;
}
-- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews
+- (void)addSubviews:(NSArray<MGLAnnotationView *> *)subviews
{
for (MGLAnnotationView *view in subviews)
{
diff --git a/platform/ios/src/MGLAnnotationContainerView_Private.h b/platform/ios/src/MGLAnnotationContainerView_Private.h
index 007b03550b..9dce54842d 100644
--- a/platform/ios/src/MGLAnnotationContainerView_Private.h
+++ b/platform/ios/src/MGLAnnotationContainerView_Private.h
@@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLAnnotationContainerView (Private)
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *annotationViews;
+@property (nonatomic) NSMutableArray<MGLAnnotationView *> *annotationViews;
@end
diff --git a/platform/ios/src/MGLCameraChangeReason.h b/platform/ios/src/MGLCameraChangeReason.h
index 6c6b3636ba..f439d3e7ea 100644
--- a/platform/ios/src/MGLCameraChangeReason.h
+++ b/platform/ios/src/MGLCameraChangeReason.h
@@ -57,5 +57,9 @@ typedef NS_OPTIONS(NSUInteger, MGLCameraChangeReason)
MGLCameraChangeReasonGestureOneFingerZoom = 1 << 7,
// :nodoc: The user panned with two fingers to tilt the map (two finger drag).
- MGLCameraChangeReasonGestureTilt = 1 << 8
+ MGLCameraChangeReasonGestureTilt = 1 << 8,
+
+ // :nodoc: Cancelled
+ MGLCameraChangeReasonTransitionCancelled = 1 << 16
+
};
diff --git a/platform/ios/src/MGLMapAccessibilityElement.mm b/platform/ios/src/MGLMapAccessibilityElement.mm
index 8bce38a145..c1cc5304d7 100644
--- a/platform/ios/src/MGLMapAccessibilityElement.mm
+++ b/platform/ios/src/MGLMapAccessibilityElement.mm
@@ -56,10 +56,8 @@
// may be in the local language, which may be written in another script.
// Attempt to transform to the script of the preferred language, keeping
// the original string if no transform exists or if transformation fails.
- if (@available(iOS 9.0, *)) {
- NSString *dominantScript = [NSOrthography mgl_dominantScriptForMapboxStreetsLanguage:languageCode];
- name = [name mgl_stringByTransliteratingIntoScript:dominantScript];
- }
+ NSString *dominantScript = [NSOrthography mgl_dominantScriptForMapboxStreetsLanguage:languageCode];
+ name = [name mgl_stringByTransliteratingIntoScript:dominantScript];
self.accessibilityLabel = name;
}
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 020dc5e830..fd0ca19b26 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -189,7 +189,7 @@ MGL_EXPORT IB_DESIGNABLE
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
-@property (nonatomic, readonly) NS_ARRAY_OF(NSURL *) *bundledStyleURLs __attribute__((unavailable("Call the relevant class method of MGLStyle for the URL of a particular default style.")));
+@property (nonatomic, readonly) NSArray<NSURL *> *bundledStyleURLs __attribute__((unavailable("Call the relevant class method of MGLStyle for the URL of a particular default style.")));
/**
URL of the style currently displayed in the receiver.
@@ -286,7 +286,7 @@ MGL_EXPORT IB_DESIGNABLE
*/
- (IBAction)showAttribution:(id)sender;
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
+@property (nonatomic) NSArray<NSString *> *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
@@ -773,7 +773,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated;
/**
Sets the visible region so that the map displays the specified annotations with
@@ -788,7 +788,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
/**
A camera representing the current viewpoint of the map.
@@ -1076,7 +1076,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view, the value of this property is
`nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *annotations;
/**
Adds an annotation to the map view.
@@ -1104,7 +1104,7 @@ MGL_EXPORT IB_DESIGNABLE
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
*/
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Removes an annotation from the map view, deselecting it if it is selected.
@@ -1129,7 +1129,7 @@ MGL_EXPORT IB_DESIGNABLE
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Returns an `MGLAnnotationView` if the given annotation is currently associated
@@ -1180,7 +1180,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view or if no annotations associated
with the map view are currently visible, the value of this property is `nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *visibleAnnotations;
/**
Returns the list of annotations associated with the receiver that intersect with
@@ -1191,7 +1191,7 @@ MGL_EXPORT IB_DESIGNABLE
no annotations associated with the map view are currently visible in the
rectangle.
*/
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect;
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect;
#pragma mark Managing Annotation Selections
@@ -1208,7 +1208,7 @@ MGL_EXPORT IB_DESIGNABLE
@note In versions prior to `4.0.0` if the annotation was offscreen it was not
selected.
*/
-@property (nonatomic, copy) NS_ARRAY_OF(id <MGLAnnotation>) *selectedAnnotations;
+@property (nonatomic, copy) NSArray<id <MGLAnnotation>> *selectedAnnotations;
/**
Selects an annotation and displays its callout view.
@@ -1246,7 +1246,7 @@ MGL_EXPORT IB_DESIGNABLE
overlays are associated with the map view, the value of this property is
empty array.
*/
-@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+@property (nonatomic, readonly, nonnull) NSArray<id <MGLOverlay>> *overlays;
/**
Adds a single overlay object to the map.
@@ -1265,7 +1265,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays;
/**
Removes a single overlay object from the map.
@@ -1285,7 +1285,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays;
#pragma mark Accessing the Underlying Map Data
@@ -1301,7 +1301,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -1320,7 +1320,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -1387,7 +1387,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1402,7 +1402,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1421,7 +1421,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1493,7 +1493,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
#pragma mark Debugging the Map
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 71f308caf0..7786d11a21 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -194,14 +194,14 @@ public:
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *scaleBarConstraints;
@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
@property (nonatomic, readwrite) UIImageView *compassView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *compassViewConstraints;
@property (nonatomic, readwrite) UIImageView *logoView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *logoViewConstraints;
@property (nonatomic, readwrite) UIButton *attributionButton;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *attributionButtonConstraints;
@property (nonatomic, readwrite) MGLStyle *style;
@@ -217,7 +217,7 @@ public:
@property (nonatomic) MGLCameraChangeReason cameraChangeReasonBitmask;
/// Mapping from reusable identifiers to annotation images.
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, MGLAnnotationImage *> *annotationImagesByIdentifier;
/// Currently shown popover representing the selected annotation.
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
@@ -235,7 +235,7 @@ public:
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@property (nonatomic) MGLUserLocation *userLocation;
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *) *annotationViewReuseQueueByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@end
@@ -287,9 +287,9 @@ public:
BOOL _delegateHasLineWidthsForShapeAnnotations;
MGLCompassDirectionFormatter *_accessibilityCompassFormatter;
- NS_ARRAY_OF(id <MGLFeature>) *_visiblePlaceFeatures;
- NS_ARRAY_OF(id <MGLFeature>) *_visibleRoadFeatures;
- NS_MUTABLE_SET_OF(MGLFeatureAccessibilityElement *) *_featureAccessibilityElements;
+ NSArray<id <MGLFeature>> *_visiblePlaceFeatures;
+ NSArray<id <MGLFeature>> *_visibleRoadFeatures;
+ NSMutableSet<MGLFeatureAccessibilityElement *> *_featureAccessibilityElements;
BOOL _accessibilityValueAnnouncementIsPending;
MGLReachability *_reachability;
@@ -335,12 +335,12 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyle
{
return [NSSet setWithObject:@"styleURL"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL
{
return [NSSet setWithObjects:@"styleURL__", nil];
}
@@ -624,18 +624,8 @@ public:
UIGraphicsBeginImageContextWithOptions(scaleImage.size, NO, [UIScreen mainScreen].scale);
[scaleImage drawInRect:{ CGPointZero, scaleImage.size }];
- CGFloat northSize = 11;
- UIFont *northFont;
- if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
- {
- northFont = [UIFont systemFontOfSize:northSize weight:UIFontWeightUltraLight];
- }
- else
- {
- northFont = [UIFont systemFontOfSize:northSize];
- }
NSAttributedString *north = [[NSAttributedString alloc] initWithString:NSLocalizedStringWithDefaultValue(@"COMPASS_NORTH", nil, nil, @"N", @"Compass abbreviation for north") attributes:@{
- NSFontAttributeName: northFont,
+ NSFontAttributeName: [UIFont systemFontOfSize:11 weight:UIFontWeightUltraLight],
NSForegroundColorAttributeName: [UIColor whiteColor],
}];
CGRect stringRect = CGRectMake((scaleImage.size.width - north.size.width) / 2,
@@ -1273,7 +1263,7 @@ public:
}
}
-- (void)touchesBegan:(__unused NS_SET_OF(UITouch *) *)touches withEvent:(__unused UIEvent *)event
+- (void)touchesBegan:(__unused NSSet<UITouch *> *)touches withEvent:(__unused UIEvent *)event
{
_changeDelimiterSuppressionDepth = 0;
_mbglMap->setGestureInProgress(false);
@@ -1281,7 +1271,7 @@ public:
{
[self setUserTrackingMode:MGLUserTrackingModeNone animated:NO];
}
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
}
- (void)notifyGestureDidBegin {
@@ -1331,7 +1321,7 @@ public:
{
if ( ! self.isScrollEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
MGLMapCamera *oldCamera = self.camera;
@@ -1400,7 +1390,7 @@ public:
{
if ( ! self.isZoomEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
CGPoint centerPoint = [self anchorPointForGesture:pinch];
MGLMapCamera *oldCamera = self.camera;
@@ -1501,7 +1491,7 @@ public:
{
if ( ! self.isRotateEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
CGPoint centerPoint = [self anchorPointForGesture:rotate];
MGLMapCamera *oldCamera = self.camera;
@@ -1706,7 +1696,7 @@ public:
{
if ( ! self.isZoomEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
if (doubleTap.state == UIGestureRecognizerStateEnded)
{
@@ -1747,7 +1737,7 @@ public:
if (_mbglMap->getZoom() == _mbglMap->getMinZoom()) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureZoomOut;
@@ -1786,7 +1776,7 @@ public:
{
if ( ! self.isZoomEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureOneFingerZoom;
@@ -1831,7 +1821,7 @@ public:
{
if ( ! self.isPitchEnabled) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureTilt;
@@ -2238,22 +2228,22 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomEnabled
{
return [NSSet setWithObject:@"allowsZooming"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingScrollEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingScrollEnabled
{
return [NSSet setWithObject:@"allowsScrolling"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingRotateEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingRotateEnabled
{
return [NSSet setWithObject:@"allowsRotating"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPitchEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPitchEnabled
{
return [NSSet setWithObject:@"allowsTilting"];
}
@@ -2419,7 +2409,7 @@ public:
return value;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visiblePlaceFeatures
+- (NSArray<id <MGLFeature>> *)visiblePlaceFeatures
{
if (!_visiblePlaceFeatures)
{
@@ -2429,7 +2419,7 @@ public:
return _visiblePlaceFeatures;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleRoadFeatures
+- (NSArray<id <MGLFeature>> *)visibleRoadFeatures
{
if (!_visibleRoadFeatures)
{
@@ -2907,7 +2897,7 @@ public:
#pragma mark - Geography -
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCenterCoordinate
{
return [NSSet setWithObjects:@"latitude", @"longitude", @"camera", nil];
}
@@ -2991,14 +2981,14 @@ public:
return;
}
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
_mbglMap->easeTo(cameraOptions, animationOptions);
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomLevel
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel
{
return [NSSet setWithObject:@"camera"];
}
@@ -3016,7 +3006,7 @@ public:
- (void)setZoomLevel:(double)zoomLevel animated:(BOOL)animated
{
if (zoomLevel == self.zoomLevel) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
@@ -3159,7 +3149,7 @@ public:
}
[self willChangeValueForKey:@"visibleCoordinateBounds"];
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
@@ -3167,7 +3157,7 @@ public:
[self didChangeValueForKey:@"visibleCoordinateBounds"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingDirection
++ (NSSet<NSString *> *)keyPathsForValuesAffectingDirection
{
return [NSSet setWithObject:@"camera"];
}
@@ -3192,7 +3182,7 @@ public:
- (void)_setDirection:(CLLocationDirection)direction animated:(BOOL)animated
{
if (direction == self.direction) return;
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
CGFloat duration = animated ? MGLAnimationDuration : 0;
@@ -3217,12 +3207,12 @@ public:
[self setDirection:direction animated:NO];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPitch
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPitch
{
return [NSSet setWithObject:@"camera"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCamera
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCamera
{
return [NSSet setWithObjects:@"longitude", @"latitude", @"centerCoordinate", @"zoomLevel", @"direction", nil];
}
@@ -3281,7 +3271,7 @@ public:
}
[self willChangeValueForKey:@"camera"];
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
@@ -3340,7 +3330,7 @@ public:
}
[self willChangeValueForKey:@"camera"];
- _mbglMap->cancelTransitions();
+ [self cancelTransitions];
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonProgrammatic;
@@ -3349,6 +3339,12 @@ public:
[self didChangeValueForKey:@"camera"];
}
+- (void)cancelTransitions {
+ self.cameraChangeReasonBitmask |= MGLCameraChangeReasonTransitionCancelled;
+ _mbglMap->cancelTransitions();
+ self.cameraChangeReasonBitmask &= ~MGLCameraChangeReasonTransitionCancelled;
+}
+
- (MGLMapCamera *)cameraThatFitsCoordinateBounds:(MGLCoordinateBounds)bounds
{
return [self cameraThatFitsCoordinateBounds:bounds edgePadding:UIEdgeInsetsZero];
@@ -3496,7 +3492,7 @@ public:
#pragma mark - Annotations -
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (nullable NSArray<id <MGLAnnotation>> *)annotations
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -3520,12 +3516,12 @@ public:
return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotations
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotations
{
return [self visibleAnnotationsInRect:self.bounds];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -3586,7 +3582,7 @@ public:
return MGLAnnotationTagNotFound;
}
- return _annotationTagsByAnnotation.at(annotation);
+ return _annotationTagsByAnnotation.at(annotation);
}
- (void)addAnnotation:(id <MGLAnnotation>)annotation
@@ -3599,7 +3595,7 @@ public:
[self addAnnotations:@[ annotation ]];
}
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations
{
if ( ! annotations) return;
[self willChangeValueForKey:@"annotations"];
@@ -3740,7 +3736,7 @@ public:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
-- (void)updateAnnotationContainerViewWithAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews
+- (void)updateAnnotationContainerViewWithAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews
{
if (annotationViews.count == 0) return;
@@ -3895,7 +3891,7 @@ public:
[self removeAnnotations:@[ annotation ]];
}
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations
{
if ( ! annotations) return;
@@ -3956,11 +3952,11 @@ public:
}
}
-- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (nonnull NSArray<id <MGLOverlay>> *)overlays
{
if (self.annotations == nil) { return @[]; }
- NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+ NSMutableArray<id <MGLOverlay>> *mutableOverlays = [NSMutableArray array];
[self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
@@ -3977,7 +3973,7 @@ public:
[self addOverlays:@[ overlay ]];
}
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays)
@@ -3994,7 +3990,7 @@ public:
[self removeOverlays:@[ overlay ]];
}
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays)
@@ -4226,13 +4222,13 @@ public:
[self didChangeValueForKey:@"selectedAnnotations"];
}
-- (NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations
+- (NSArray<id <MGLAnnotation>> *)selectedAnnotations
{
id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
return (selectedAnnotation ? @[ selectedAnnotation ] : @[]);
}
-- (void)setSelectedAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations
+- (void)setSelectedAnnotations:(NSArray<id <MGLAnnotation>> *)selectedAnnotations
{
if ( ! selectedAnnotations.count) return;
@@ -4599,7 +4595,7 @@ public:
completion:NULL];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated
{
CGFloat maximumPadding = 100;
CGFloat yPadding = (self.frame.size.height / 5 <= maximumPadding) ? (self.frame.size.height / 5) : maximumPadding;
@@ -4610,7 +4606,7 @@ public:
[self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated
{
if ( ! annotations || ! annotations.count) return;
@@ -4798,7 +4794,7 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingUserLocation
++ (NSSet<NSString *> *)keyPathsForValuesAffectingUserLocation
{
return [NSSet setWithObject:@"userLocationAnnotationView"];
}
@@ -5289,16 +5285,16 @@ public:
#pragma mark Data
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point
{
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate
{
mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y };
@@ -5323,15 +5319,15 @@ public:
return MGLFeaturesFromMBGLFeatures(features);
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
mbgl::ScreenBox screenBox = {
{ CGRectGetMinX(rect), CGRectGetMinY(rect) },
{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) },
@@ -5757,21 +5753,18 @@ public:
if (tag != MGLAnnotationTagNotFound) {
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
annotationView = annotationContext.annotationView;
+ } else if (annotation == self.userLocation) {
+ annotationView = self.userLocationAnnotationView;
}
- CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];
-
- if (annotationView)
- {
- rect = annotationView.frame;
- }
+ CGRect positioningRect = annotationView ? annotationView.frame : [self positioningRectForCalloutForAnnotationWithTag:tag];
- NSAssert(!CGRectIsNull(rect), @"Positioning rect should not be CGRectNull by this point");
+ NSAssert( ! CGRectIsNull(positioningRect), @"Positioning rect should not be CGRectNull by this point");
- CGPoint point = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
+ CGPoint centerPoint = CGPointMake(CGRectGetMidX(positioningRect), CGRectGetMinY(positioningRect));
- if ( ! CGPointEqualToPoint(calloutView.center, point)) {
- calloutView.center = point;
+ if ( ! CGPointEqualToPoint(calloutView.center, centerPoint)) {
+ calloutView.center = centerPoint;
}
}
}
@@ -5844,19 +5837,6 @@ public:
annotationView.hidden = NO;
[annotationView update];
-
- if (_userLocationAnnotationIsSelected)
- {
- // Ensure the callout view still points to its annotation.
- UIView <MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
- CGRect calloutFrame = calloutView.frame;
- calloutFrame.origin.x = annotationView.center.x - CGRectGetWidth(calloutFrame) / 2;
- calloutFrame.origin.y = CGRectGetMinY(annotationView.frame) - CGRectGetHeight(calloutFrame);
- if ( ! CGRectEqualToRect(calloutView.frame, calloutFrame))
- {
- calloutView.frame = calloutFrame;
- }
- }
}
else
{
@@ -6065,7 +6045,7 @@ public:
views:views]];
}
-- (NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *)annotationViewReuseQueueForIdentifier:(NSString *)identifier {
+- (NSMutableArray<MGLAnnotationView *> *)annotationViewReuseQueueForIdentifier:(NSString *)identifier {
if (!_annotationViewReuseQueueByIdentifier[identifier])
{
_annotationViewReuseQueueByIdentifier[identifier] = [NSMutableArray array];
@@ -6222,7 +6202,7 @@ private:
@implementation MGLMapView (IBAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL__
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL__
{
return [NSSet setWithObject:@"styleURL"];
}
@@ -6245,7 +6225,7 @@ private:
self.styleURL = url;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLatitude
{
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -6271,7 +6251,7 @@ private:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLongitude
{
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -6297,7 +6277,7 @@ private:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsZooming
{
return [NSSet setWithObject:@"zoomEnabled"];
}
@@ -6312,7 +6292,7 @@ private:
self.zoomEnabled = allowsZooming;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsScrolling
{
return [NSSet setWithObject:@"scrollEnabled"];
}
@@ -6327,7 +6307,7 @@ private:
self.scrollEnabled = allowsScrolling;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsRotating
{
return [NSSet setWithObject:@"rotateEnabled"];
}
@@ -6342,7 +6322,7 @@ private:
self.rotateEnabled = allowsRotating;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsTilting
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsTilting
{
return [NSSet setWithObject:@"pitchEnabled"];
}
@@ -6357,7 +6337,7 @@ private:
self.pitchEnabled = allowsTilting;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingShowsHeading
++ (NSSet<NSString *> *)keyPathsForValuesAffectingShowsHeading
{
return [NSSet setWithObject:@"showsUserHeadingIndicator"];
}
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 0368d8413c..201e3db84b 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -428,7 +428,7 @@ NS_ASSUME_NONNULL_BEGIN
@param annotationViews An array of `MGLAnnotationView` objects representing the
views that were added.
*/
-- (void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews;
+- (void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews;
#pragma mark Selecting Annotations
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
index 139dffdfab..d69fb3e852 100644
--- a/platform/ios/src/MGLScaleBar.mm
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -75,7 +75,7 @@ static const MGLRow MGLImperialTable[] ={
@class MGLScaleBarLabel;
@interface MGLScaleBar()
-@property (nonatomic) NSArray<MGLScaleBarLabel *> *labels;
+@property (nonatomic) NSArray<UIView *> *labelViews;
@property (nonatomic) NSArray<UIView *> *bars;
@property (nonatomic) UIView *containerView;
@property (nonatomic) MGLDistanceFormatter *formatter;
@@ -84,6 +84,10 @@ static const MGLRow MGLImperialTable[] ={
@property (nonatomic) UIColor *secondaryColor;
@property (nonatomic) CALayer *borderLayer;
@property (nonatomic, assign) CGFloat borderWidth;
+@property (nonatomic) NSCache* labelImageCache;
+@property (nonatomic) MGLScaleBarLabel* prototypeLabel;
+
+
@end
static const CGFloat MGLBarHeight = 4;
@@ -152,6 +156,29 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
[_containerView.layer addSublayer:_borderLayer];
_formatter = [[MGLDistanceFormatter alloc] init];
+
+ // Image labels are now images
+ _labelImageCache = [[NSCache alloc] init];
+ _prototypeLabel = [[MGLScaleBarLabel alloc] init];
+ _prototypeLabel.font = [UIFont systemFontOfSize:8 weight:UIFontWeightMedium];
+ _prototypeLabel.clipsToBounds = NO;
+
+ NSUInteger numberOfLabels = 4;
+ NSMutableArray *labelViews = [NSMutableArray arrayWithCapacity:numberOfLabels];
+
+ for (NSUInteger i = 0; i < numberOfLabels; i++) {
+ UIView *view = [[UIView alloc] init];
+ view.bounds = CGRectZero;
+ view.clipsToBounds = NO;
+ view.contentMode = UIViewContentModeCenter;
+ view.hidden = YES;
+ [labelViews addObject:view];
+ [self addSubview:view];
+ }
+ _labelViews = [labelViews copy];
+
+ // Zero is a special case (no formatting)
+ [self addZeroLabel];
}
#pragma mark - Dimensions
@@ -178,12 +205,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
#pragma mark - Convenience methods
- (BOOL)usesRightToLeftLayout {
- // semanticContentAttribute is iOS 9+
- if ([self.superview respondsToSelector:@selector(semanticContentAttribute)]) {
- return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
- } else {
- return UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
- }
+ return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
}
- (BOOL)usesMetricSystem {
@@ -195,21 +217,31 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
CLLocationDistance maximumDistance = [self maximumWidth] * [self unitsPerPoint];
BOOL useMetric = [self usesMetricSystem];
- MGLRow row = useMetric ? MGLMetricTable[0] : MGLImperialTable[0];
- NSUInteger count = useMetric
- ? sizeof(MGLMetricTable) / sizeof(MGLMetricTable[0])
- : sizeof(MGLImperialTable) / sizeof(MGLImperialTable[0]);
-
- for (NSUInteger i = 0; i < count; i++) {
- CLLocationDistance distance = useMetric ? MGLMetricTable[i].distance : MGLImperialTable[i].distance;
- if (distance <= maximumDistance) {
- row = useMetric ? MGLMetricTable[i] : MGLImperialTable[i];
- } else {
- break;
+
+ const MGLRow *row;
+ const MGLRow *table;
+ NSUInteger count;
+
+ if (useMetric) {
+ row = table = MGLMetricTable;
+ count = sizeof(MGLMetricTable) / sizeof(MGLMetricTable[0]);
+ }
+ else {
+ row = table = MGLImperialTable;
+ count = sizeof(MGLImperialTable) / sizeof(MGLImperialTable[0]);
+ }
+
+ while (row < table + count) {
+ if (row->distance > maximumDistance) {
+ // use the previous row
+ NSAssert(row != table, @"");
+ return *(row - 1);
}
+ ++row;
}
-
- return row;
+
+ // Didn't find it, just return the first.
+ return *table;
}
#pragma mark - Setters
@@ -260,9 +292,9 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
_row = row;
[_bars makeObjectsPerformSelector:@selector(removeFromSuperview)];
- [_labels makeObjectsPerformSelector:@selector(removeFromSuperview)];
_bars = nil;
- _labels = nil;
+
+ [self updateLabels];
}
#pragma mark - Views
@@ -280,61 +312,91 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
return _bars;
}
-- (NSArray<UILabel *> *)labels {
- if (!_labels) {
- NSDecimalNumber *zeroNumber = [NSDecimalNumber decimalNumberWithString:@"0"];
- NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
- NSMutableArray *labels = [NSMutableArray array];
-
- for (NSUInteger i = 0; i <= self.row.numberOfBars; i++) {
- UILabel *label = [[MGLScaleBarLabel alloc] init];
- label.font = [UIFont systemFontOfSize:8 weight:UIFontWeightMedium];
- label.text = [formatter stringFromNumber:zeroNumber];
- label.clipsToBounds = NO;
- [label setNeedsDisplay];
- [label sizeToFit];
- [labels addObject:label];
- [self addSubview:label];
- }
- _labels = labels;
+#pragma mark - Labels
+
+- (void)addZeroLabel {
+ NSDecimalNumber *zeroNumber = [NSDecimalNumber decimalNumberWithString:@"0"];
+ NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
+ NSString *text = [formatter stringFromNumber:zeroNumber];
+
+ UIImage* image = [self imageForLabelText:text];
+ [self.labelImageCache setObject:image forKey:@(0)];
+}
+
+- (UIImage*)imageForLabelText:(NSString*)text {
+ self.prototypeLabel.text = text;
+ [self.prototypeLabel setNeedsDisplay];
+ [self.prototypeLabel sizeToFit];
+
+ // Now render
+ UIGraphicsBeginImageContextWithOptions(self.prototypeLabel.bounds.size, NO, 0.0);
+ [self.prototypeLabel.layer renderInContext: UIGraphicsGetCurrentContext()];
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ return image;
+}
+
+- (UIImage*)cachedLabelImageForDistance:(CLLocationDistance)barDistance {
+ // Make a slightly nicer key, rather than something that's a double.
+ NSUInteger floorDist = (NSUInteger)(barDistance*100);
+
+ NSNumber *key = @(floorDist);
+ UIImage *cachedImage = [self.labelImageCache objectForKey:key];
+
+ if (cachedImage) {
+ return cachedImage;
+ }
+
+ // Calc it
+ NSString *text = [self.formatter stringFromDistance:barDistance];
+ UIImage *image = [self imageForLabelText:text];
+
+ [self.labelImageCache setObject:image forKey:key];
+
+ return image;
+}
+
+- (void)updateLabels {
+ NSEnumerator<UIView*> *viewEnumerator = [self.labelViews objectEnumerator];
+ NSInteger i = 0;
+ CLLocationDistance multiplier = (self.row.distance / self.row.numberOfBars);
+
+ if (![self usesMetricSystem]) {
+ multiplier /= MGLFeetPerMeter;
+ }
+
+ for (; i <= self.row.numberOfBars; i++) {
+ UIView *labelView = [viewEnumerator nextObject];
+ labelView.hidden = NO;
+
+ CLLocationDistance barDistance = multiplier * i;
+ UIImage *image = [self cachedLabelImageForDistance:barDistance];
+
+ labelView.layer.contents = (id)image.CGImage;
+ labelView.layer.contentsScale = image.scale;
+ }
+
+ // Hide the rest.
+ for (; i < self.labelViews.count; i++) {
+ UIView *labelView = [viewEnumerator nextObject];
+ labelView.hidden = YES;
}
- return _labels;
}
#pragma mark - Layout
- (void)layoutSubviews {
[super layoutSubviews];
-
+
if (!self.row.numberOfBars) {
// Current distance is not within allowed range
return;
}
-
- [self updateLabels];
+
[self layoutBars];
[self layoutLabels];
}
-- (void)updateLabels {
- NSArray *labels = [self.labels subarrayWithRange:NSMakeRange(1, self.labels.count-1)];
- BOOL useMetric = [self usesMetricSystem];
- NSUInteger i = 0;
-
- for (MGLScaleBarLabel *label in labels) {
- CLLocationDistance barDistance = (self.row.distance / self.row.numberOfBars) * (i + 1);
-
- if (!useMetric) {
- barDistance /= MGLFeetPerMeter;
- }
-
- label.text = [self.formatter stringFromDistance:barDistance];
- [label setNeedsDisplay];
- [label sizeToFit];
- i++;
- }
-}
-
- (void)layoutBars {
CGFloat barWidth = round((CGRectGetWidth(self.bounds) - self.borderWidth * 2.0f) / self.bars.count);
@@ -362,11 +424,15 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
CGFloat barWidth = round(self.bounds.size.width / self.bars.count);
BOOL RTL = [self usesRightToLeftLayout];
NSUInteger i = RTL ? self.bars.count : 0;
- for (MGLScaleBarLabel *label in self.labels) {
+ for (UIView *label in self.labelViews) {
CGFloat xPosition = round(barWidth * i - CGRectGetMidX(label.bounds) + self.borderWidth);
- label.frame = CGRectMake(xPosition, 0,
- CGRectGetWidth(label.bounds),
- CGRectGetHeight(label.bounds));
+ CGFloat yPosition = round(0.5 * (CGRectGetMaxY(self.bounds) - MGLBarHeight));
+
+ CGRect frame = label.frame;
+ frame.origin.x = xPosition;
+ frame.origin.y = yPosition;
+ label.frame = frame;
+
i = RTL ? i-1 : i+1;
}
}
diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m
index 074d138a72..245cbf4371 100644
--- a/platform/ios/src/MGLUserLocation.m
+++ b/platform/ios/src/MGLUserLocation.m
@@ -68,7 +68,7 @@ NS_ASSUME_NONNULL_END
return ! [key isEqualToString:@"location"] && ! [key isEqualToString:@"heading"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCoordinate
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCoordinate
{
return [NSSet setWithObject:@"location"];
}
diff --git a/platform/ios/test/MGLAnnotationViewTests.m b/platform/ios/test/MGLAnnotationViewTests.m
index a2cc4227ed..7bf7c90a33 100644
--- a/platform/ios/test/MGLAnnotationViewTests.m
+++ b/platform/ios/test/MGLAnnotationViewTests.m
@@ -1,5 +1,6 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLTestUtility.h"
static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer";
@@ -209,7 +210,8 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
XCTAssertEqual(view.dragState, MGLAnnotationViewDragStateNone);
}
-- (void)testAnnotationViewInitWithFrame {
+- (void)testAnnotationViewInitWithFramePENDING {
+ MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN();
CGRect frame = CGRectMake(10.0, 10.0, 100.0, 100.0);
MGLAnnotationView *view = [[MGLAnnotationView alloc] initWithFrame:frame];
[self checkDefaultPropertiesForAnnotationView:view];
@@ -220,11 +222,12 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
[self checkDefaultPropertiesForAnnotationView:view];
}
-- (void)testSelectingADisabledAnnotationView {
+- (void)testSelectingADisabledAnnotationViewPENDING {
+ MGL_CHECK_IF_PENDING_TEST_SHOULD_RUN();
self.prepareAnnotationView = ^(MGLAnnotationView *view) {
view.enabled = NO;
};
-
+
// Create annotation
MGLPointFeature *point = [[MGLPointFeature alloc] init];
point.title = NSStringFromSelector(_cmd);
diff --git a/platform/ios/test/MGLMapAccessibilityElementTests.m b/platform/ios/test/MGLMapAccessibilityElementTests.m
index 89a595421e..916461e708 100644
--- a/platform/ios/test/MGLMapAccessibilityElementTests.m
+++ b/platform/ios/test/MGLMapAccessibilityElementTests.m
@@ -25,11 +25,7 @@
@"name_en": @"Цинциннати",
};
element = [[MGLFeatureAccessibilityElement alloc] initWithAccessibilityContainer:self feature:feature];
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects(element.accessibilityLabel, @"Cincinnati", @"Accessibility label should be romanized.");
- } else {
- XCTAssertEqualObjects(element.accessibilityLabel, @"Цинциннати", @"Accessibility label should not be romanized.");
- }
+ XCTAssertEqualObjects(element.accessibilityLabel, @"Cincinnati", @"Accessibility label should be romanized.");
}
- (void)testPlaceFeatureValues {
diff --git a/platform/ios/uitest/.gitignore b/platform/ios/uitest/.gitignore
deleted file mode 100644
index 516812b72d..0000000000
--- a/platform/ios/uitest/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-!*.xcodeproj
-!xcshareddata
-xcuserdata
diff --git a/platform/ios/uitest/App-Info.plist b/platform/ios/uitest/App-Info.plist
deleted file mode 100644
index ab5ac7ec8c..0000000000
--- a/platform/ios/uitest/App-Info.plist
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleDisplayName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>APPL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1.0</string>
- <key>LSRequiresIPhoneOS</key>
- <true/>
- <key>MGLMapboxAccessToken</key>
- <string>pk.eyJ1IjoianVzdGluIiwiYSI6Ik9RX3RRQzAifQ.dmOg_BAp1ywuDZMM7YsXRg</string>
- <key>MGLMapboxMetricsEnabledSettingShownInApp</key>
- <true/>
- <key>NSLocationAlwaysUsageDescription</key>
- <string>Strictly for testing purposes, promise!</string>
- <key>UILaunchStoryboardName</key>
- <string>LaunchScreen</string>
- <key>UIRequiredDeviceCapabilities</key>
- <array>
- <string>armv7</string>
- </array>
- <key>UISupportedInterfaceOrientations</key>
- <array>
- <string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
- </array>
- <key>UISupportedInterfaceOrientations~ipad</key>
- <array>
- <string>UIInterfaceOrientationPortrait</string>
- <string>UIInterfaceOrientationPortraitUpsideDown</string>
- <string>UIInterfaceOrientationLandscapeLeft</string>
- <string>UIInterfaceOrientationLandscapeRight</string>
- </array>
-</dict>
-</plist>
diff --git a/platform/ios/uitest/Bundle-Info.plist b/platform/ios/uitest/Bundle-Info.plist
deleted file mode 100644
index 169b6f710e..0000000000
--- a/platform/ios/uitest/Bundle-Info.plist
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>CFBundleDevelopmentRegion</key>
- <string>en</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundlePackageType</key>
- <string>BNDL</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
-</dict>
-</plist>
diff --git a/platform/ios/uitest/Images.xcassets/AppIcon.appiconset/Contents.json b/platform/ios/uitest/Images.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644
index eeea76c2db..0000000000
--- a/platform/ios/uitest/Images.xcassets/AppIcon.appiconset/Contents.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "29x29",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "40x40",
- "scale" : "3x"
- },
- {
- "idiom" : "iphone",
- "size" : "60x60",
- "scale" : "2x"
- },
- {
- "idiom" : "iphone",
- "size" : "60x60",
- "scale" : "3x"
- },
- {
- "idiom" : "ipad",
- "size" : "29x29",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "29x29",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "40x40",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "40x40",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "76x76",
- "scale" : "1x"
- },
- {
- "idiom" : "ipad",
- "size" : "76x76",
- "scale" : "2x"
- },
- {
- "idiom" : "ipad",
- "size" : "83.5x83.5",
- "scale" : "2x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-} \ No newline at end of file
diff --git a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Contents.json b/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Contents.json
deleted file mode 100644
index 628027f247..0000000000
--- a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Contents.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "images" : [
- {
- "orientation" : "portrait",
- "idiom" : "iphone",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "filename" : "Default@2x.png",
- "scale" : "2x"
- },
- {
- "extent" : "full-screen",
- "idiom" : "iphone",
- "subtype" : "retina4",
- "filename" : "Default-568h@2x.png",
- "minimum-system-version" : "7.0",
- "orientation" : "portrait",
- "scale" : "2x"
- },
- {
- "orientation" : "portrait",
- "idiom" : "ipad",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "scale" : "1x"
- },
- {
- "orientation" : "landscape",
- "idiom" : "ipad",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "scale" : "1x"
- },
- {
- "orientation" : "portrait",
- "idiom" : "ipad",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "scale" : "2x"
- },
- {
- "orientation" : "landscape",
- "idiom" : "ipad",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "scale" : "2x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-} \ No newline at end of file
diff --git a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
deleted file mode 100644
index 208eea205a..0000000000
--- a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default@2x.png b/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default@2x.png
deleted file mode 100644
index 4438336215..0000000000
--- a/platform/ios/uitest/Images.xcassets/LaunchImage.launchimage/Default@2x.png
+++ /dev/null
Binary files differ
diff --git a/platform/ios/uitest/KIF b/platform/ios/uitest/KIF
deleted file mode 160000
-Subproject c40b1048a6f35c6fd90376846a1a933844516b3
diff --git a/platform/ios/uitest/KIFTestActor+MapboxGL.h b/platform/ios/uitest/KIFTestActor+MapboxGL.h
deleted file mode 100644
index d16e348486..0000000000
--- a/platform/ios/uitest/KIFTestActor+MapboxGL.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#import <UIKit/UIKit.h>
-#import <KIF/KIF.h>
-
-@class MGLTViewController, MGLMapView;
-
-@interface KIFTestActor (MapboxGL)
-
-@property (nonatomic, readonly) UIWindow *window;
-@property (nonatomic, readonly) MGLTViewController *viewController;
-@property (nonatomic, readonly) MGLMapView *mapView;
-@property (nonatomic, readonly) UIView *compass;
-
-@end
diff --git a/platform/ios/uitest/KIFTestActor+MapboxGL.m b/platform/ios/uitest/KIFTestActor+MapboxGL.m
deleted file mode 100644
index 6c5e53f40d..0000000000
--- a/platform/ios/uitest/KIFTestActor+MapboxGL.m
+++ /dev/null
@@ -1,25 +0,0 @@
-#import "KIFTestActor+MapboxGL.h"
-
-#import <Mapbox/Mapbox.h>
-
-#import <KIF/UIApplication-KIFAdditions.h>
-
-@implementation KIFTestActor (MapboxGL)
-
-- (UIWindow *)window {
- return [[UIApplication sharedApplication] statusBarWindow];
-}
-
-- (MGLTViewController *)viewController {
- return (MGLTViewController *)[[tester.mapView nextResponder] nextResponder];
-}
-
-- (MGLMapView *)mapView {
- return (MGLMapView *)[tester waitForViewWithAccessibilityLabel:@"Map"];
-}
-
-- (UIView *)compass {
- return [tester waitForViewWithAccessibilityLabel:@"Compass"];
-}
-
-@end
diff --git a/platform/ios/uitest/LaunchScreen.xib b/platform/ios/uitest/LaunchScreen.xib
deleted file mode 100644
index dd23975342..0000000000
--- a/platform/ios/uitest/LaunchScreen.xib
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E17e" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
- <dependencies>
- <deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
- <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
- </dependencies>
- <objects>
- <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
- <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
- <view contentMode="scaleToFill" id="iN0-l3-epB">
- <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <subviews>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="© 2015–2018 Mapbox. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
- <rect key="frame" x="20" y="439" width="441" height="21"/>
- <fontDescription key="fontDescription" type="system" pointSize="17"/>
- <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
- <nil key="highlightedColor"/>
- <variation key="widthClass=compact">
- <fontDescription key="fontDescription" type="system" pointSize="11"/>
- </variation>
- </label>
- <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ios-tests" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
- <rect key="frame" x="20" y="140" width="441" height="43"/>
- <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
- <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
- <nil key="highlightedColor"/>
- </label>
- </subviews>
- <color key="backgroundColor" red="0.23137254900000001" green="0.69803921570000005" blue="0.81568627449999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- <constraints>
- <constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="Kid-kn-2rF"/>
- <constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
- <constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
- <constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
- <constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
- <constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
- </constraints>
- <nil key="simulatedStatusBarMetrics"/>
- <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
- <point key="canvasLocation" x="404" y="445"/>
- </view>
- </objects>
-</document>
diff --git a/platform/ios/uitest/MGLTAppDelegate.h b/platform/ios/uitest/MGLTAppDelegate.h
deleted file mode 100644
index c0025582ee..0000000000
--- a/platform/ios/uitest/MGLTAppDelegate.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#import <UIKit/UIKit.h>
-
-@interface MGLTAppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (nonatomic) UIWindow *window;
-
-@end
diff --git a/platform/ios/uitest/MGLTAppDelegate.m b/platform/ios/uitest/MGLTAppDelegate.m
deleted file mode 100644
index b79c2f4abb..0000000000
--- a/platform/ios/uitest/MGLTAppDelegate.m
+++ /dev/null
@@ -1,19 +0,0 @@
-#import "MGLTAppDelegate.h"
-#import "MGLTViewController.h"
-#import <Mapbox/Mapbox.h>
-
-@implementation MGLTAppDelegate
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
- self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- UINavigationController *wrapper = [[UINavigationController alloc] initWithRootViewController:[MGLTViewController new]];
- self.window.rootViewController = wrapper;
- wrapper.navigationBarHidden = YES;
- wrapper.toolbarHidden = YES;
- [self.window makeKeyAndVisible];
-
- return YES;
-}
-
-@end
diff --git a/platform/ios/uitest/MGLTViewController.h b/platform/ios/uitest/MGLTViewController.h
deleted file mode 100644
index 349c216008..0000000000
--- a/platform/ios/uitest/MGLTViewController.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#import <UIKit/UIKit.h>
-
-@interface MGLTViewController : UIViewController
-
-- (void)insetMapView;
-- (void)tinyMapView;
-- (void)resetMapView;
-
-@end
diff --git a/platform/ios/uitest/MGLTViewController.m b/platform/ios/uitest/MGLTViewController.m
deleted file mode 100644
index 451dea9292..0000000000
--- a/platform/ios/uitest/MGLTViewController.m
+++ /dev/null
@@ -1,34 +0,0 @@
-#import "MGLTViewController.h"
-#import <Mapbox/Mapbox.h>
-
-@implementation MGLTViewController
-{
- MGLMapView *_mapView;
-}
-
-- (void)viewDidLoad
-{
- [super viewDidLoad];
-
- _mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
- _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self.view addSubview:_mapView];
-}
-
-- (void)insetMapView
-{
- _mapView.frame = CGRectInset(_mapView.frame, 50, 50);
-}
-
-- (void)tinyMapView
-{
- _mapView.frame = CGRectMake(20, self.topLayoutGuide.length, self.view.frame.size.width / 2, self.view.frame.size.height / 2);
-}
-
-- (void)resetMapView
-{
- _mapView.frame = self.view.bounds;
-}
-
-@end
diff --git a/platform/ios/uitest/MapViewTests.m b/platform/ios/uitest/MapViewTests.m
deleted file mode 100644
index ba15af918a..0000000000
--- a/platform/ios/uitest/MapViewTests.m
+++ /dev/null
@@ -1,588 +0,0 @@
-#import <KIF/KIF.h>
-#import <KIF/KIFTestStepValidation.h>
-
-#import "KIFTestActor+MapboxGL.h"
-
-#import <Mapbox/Mapbox.h>
-#import "MGLTViewController.h"
-
-#import <CoreLocation/CoreLocation.h>
-
-@interface MapViewTests : KIFTestCase <MGLMapViewDelegate>
-
-@end
-
-@implementation MapViewTests
-
-- (NSNotification *)waitForNotificationThatRegionDidChangeAnimatedWhileExecutingBlock:(void (^)())block {
- [[NSNotificationCenter defaultCenter] addObserverForName:@"regionDidChangeAnimated"
- object:tester.mapView
- queue:nil
- usingBlock:^(NSNotification * _Nonnull note) {}];
- NSNotification *notification = [system waitForNotificationName:@"regionDidChangeAnimated"
- object:tester.mapView whileExecutingBlock:block];
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"regionDidChangeAnimated"
- object:tester.mapView];
- return notification;
-}
-
-- (void)beforeEach {
- [system simulateDeviceRotationToOrientation:UIDeviceOrientationPortrait];
- [tester.viewController resetMapView];
-
- tester.mapView.centerCoordinate = CLLocationCoordinate2DMake(38.913175, -77.032458);
- tester.mapView.zoomLevel = 14;
- tester.mapView.direction = 0;
-
- tester.mapView.zoomEnabled = YES;
- tester.mapView.scrollEnabled = YES;
- tester.mapView.rotateEnabled = YES;
-
- [tester.mapView removeAnnotations:tester.mapView.annotations];
-
- tester.viewController.navigationController.navigationBarHidden = YES;
- tester.viewController.navigationController.toolbarHidden = YES;
-
- tester.mapView.delegate = self;
-}
-
-- (void)approveLocationIfNeeded {
- if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
- [tester acknowledgeSystemAlert];
- [tester waitForTimeInterval:1];
- }
- XCTAssertTrue([CLLocationManager locationServicesEnabled]);
- XCTAssertEqual([CLLocationManager authorizationStatus], kCLAuthorizationStatusAuthorizedAlways);
-}
-
-- (void)testDirectionSet {
- [self waitForNotificationThatRegionDidChangeAnimatedWhileExecutingBlock:^{
- [tester.mapView setDirection:270 animated:YES];
- }];
-
- XCTAssertEqual(tester.mapView.direction,
- 270,
- @"setting direction should take effect");
-
- [tester waitForAnimationsToFinish];
- XCTAssertEqual(tester.compass.alpha,
- 1,
- @"compass should be visible when map is rotated");
-
- XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform],
- [NSValue valueWithCGAffineTransform:CGAffineTransformMakeRotation(M_PI * 0.5)],
- @"compass rotation should indicate map rotation");
-}
-
-- (void)testDirectionReset {
- [self waitForNotificationThatRegionDidChangeAnimatedWhileExecutingBlock:^{
- [tester.mapView setDirection:90 animated:YES];
- }];
-
- XCTAssertEqual(tester.mapView.direction,
- 90,
- @"setting direction should take effect");
-
- [self waitForNotificationThatRegionDidChangeAnimatedWhileExecutingBlock:^{
- [tester.mapView resetNorth];
- }];
-
- XCTAssertEqual(tester.mapView.direction,
- 0,
- @"resetting north should reset map direction");
-
- [tester waitForAnimationsToFinish];
- XCTAssertEqual(tester.compass.alpha,
- 0,
- @"compass should not be visible when map is unrotated");
-
- XCTAssert(CGAffineTransformEqualToTransform(tester.compass.transform, CGAffineTransformIdentity),
- @"compass rotation should indicate map rotation");
-}
-
-- (void)testZoom {
- double zoom = tester.mapView.zoomLevel;
-
- [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2,
- tester.mapView.bounds.size.height / 2)
- distance:50
- steps:10];
-
- XCTAssertGreaterThan(tester.mapView.zoomLevel,
- zoom,
- @"zoom gesture should increase zoom level");
-
- zoom = tester.mapView.zoomLevel;
-
- [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2,
- tester.mapView.bounds.size.height / 2)
- distance:50
- steps:10];
-
- XCTAssertLessThan(tester.mapView.zoomLevel,
- zoom,
- @"pinch gesture should decrease zoom level");
-}
-
-- (void)testZoomDisabled {
- tester.mapView.zoomEnabled = NO;
- double zoom = tester.mapView.zoomLevel;
-
- [tester.mapView zoomAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2,
- tester.mapView.bounds.size.height / 2)
- distance:50
- steps:10];
-
- XCTAssertEqual(tester.mapView.zoomLevel,
- zoom,
- @"disabling zoom gesture should disallow zooming");
-
- [tester.mapView pinchAtPoint:CGPointMake(tester.mapView.bounds.size.width / 2,
- tester.mapView.bounds.size.height / 2)
- distance:50
- steps:10];
-
- XCTAssertEqual(tester.mapView.zoomLevel,
- zoom,
- @"disabling zoom gesture should disallow pinching");
-}
-
-- (void)testFitToBounds {
- // No-op
- MGLCoordinateBounds initialBounds = tester.mapView.visibleCoordinateBounds;
- [tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
- XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
- @"setting visible coordinate bounds to currently visible coordinate bounds should be a no-op");
-
- // Roundtrip after zooming
- tester.mapView.zoomLevel -= 3;
- [tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
- XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
- @"after zooming out, setting visible coordinate bounds back to %@ should not leave them at %@",
- MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
- tester.mapView.zoomLevel += 3;
- [tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
- XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
- @"after zooming in, setting visible coordinate bounds back to %@ should not leave them at %@",
- MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
-
- // Roundtrip after panning
- MGLCoordinateBounds offsetBounds = MGLCoordinateBoundsOffset(initialBounds, MGLCoordinateSpanMake(0, 30));
- [tester.mapView setVisibleCoordinateBounds:offsetBounds animated:NO];
- [tester.mapView setVisibleCoordinateBounds:initialBounds animated:NO];
- XCTAssertEqualObjects(MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds),
- @"after panning 30° to the east, setting visible coordinate bounds back to %@ should not leave them at %@",
- MGLStringFromCoordinateBounds(initialBounds),
- MGLStringFromCoordinateBounds(tester.mapView.visibleCoordinateBounds));
-
- // Inscribed shapes with rotation
- tester.mapView.direction = 45;
- // https://en.wikipedia.org/wiki/Boundary_Markers_of_the_Original_District_of_Columbia
- CLLocationCoordinate2D dcCoordinates[] = {
- {38.790339, -77.040583},
- {38.893219, -77.172304},
- {38.995946, -77.040947},
- {38.892829, -76.909229},
- };
- MGLCoordinateBounds dcBounds = {{38.790339, -77.172304}, {38.995946, -76.909229}};
- [tester.mapView setVisibleCoordinateBounds:dcBounds
- animated:NO];
- double zoomLevel = tester.mapView.zoomLevel;
- [tester.mapView setVisibleCoordinates:dcCoordinates
- count:sizeof(dcCoordinates) / sizeof(dcCoordinates[0])
- edgePadding:UIEdgeInsetsZero
- animated:NO];
- XCTAssertGreaterThan(tester.mapView.zoomLevel, zoomLevel,
- @"when the map is rotated, DC should fit at a zoom level higher than %f, but instead the zoom level is %f",
- zoomLevel, tester.mapView.zoomLevel);
-}
-
-- (void)testPan {
- CLLocationCoordinate2D centerCoordinate = tester.mapView.centerCoordinate;
-
- [tester.mapView dragFromPoint:CGPointMake(10, 10) toPoint:CGPointMake(300, 300) steps:10];
-
- XCTAssertGreaterThan(tester.mapView.centerCoordinate.latitude,
- centerCoordinate.latitude,
- @"panning map down should increase center latitude");
-
- XCTAssertLessThan(tester.mapView.centerCoordinate.longitude,
- centerCoordinate.longitude,
- @"panning map right should decrease center longitude");
-}
-
-- (void)testSetCenterCancelsTransitions {
- XCTestExpectation *cameraIsInDCExpectation = [self expectationWithDescription:@"camera reset to DC"];
-
- CLLocationCoordinate2D dc = CLLocationCoordinate2DMake(38.894368, -77.036487);
- CLLocationCoordinate2D dc_west = CLLocationCoordinate2DMake(38.894368, -77.076487);
- [tester.mapView setCenterCoordinate:dc animated:NO];
- [tester.mapView setCenterCoordinate:dc_west animated:YES];
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.15 * NSEC_PER_SEC),
- dispatch_get_main_queue(),
- ^{
- [tester.mapView setCenterCoordinate:dc animated:NO];
- XCTAssertEqualWithAccuracy(dc.latitude,
- tester.mapView.centerCoordinate.latitude,
- 0.0005,
- @"setting center coordinate should cancel transitions");
- XCTAssertEqualWithAccuracy(dc.longitude,
- tester.mapView.centerCoordinate.longitude,
- 0.0005,
- @"setting center coordinate should cancel transitions");
- [cameraIsInDCExpectation fulfill];
- });
-
- [self waitForExpectationsWithTimeout:1.0 handler:nil];
-}
-
-- (void)testPanDisabled {
- tester.mapView.scrollEnabled = NO;
- CLLocationCoordinate2D centerCoordinate = tester.mapView.centerCoordinate;
-
- [tester.mapView dragFromPoint:CGPointMake(10, 10) toPoint:CGPointMake(300, 300) steps:10];
-
- XCTAssertEqualWithAccuracy(centerCoordinate.latitude,
- tester.mapView.centerCoordinate.latitude,
- 0.005,
- @"disabling pan gesture should disallow vertical panning");
-
- XCTAssertEqualWithAccuracy(centerCoordinate.longitude,
- tester.mapView.centerCoordinate.longitude,
- 0.005,
- @"disabling pan gesture should disallow horizontal panning");
-}
-
-- (void)testRotateClockwise {
- CLLocationDirection startAngle = tester.mapView.direction;
-
- XCTAssertNotEqual(startAngle,
- 45,
- @"start angle must not be destination angle");
-
- [tester.mapView twoFingerRotateAtPoint:tester.mapView.center angle:45];
-
- XCTAssertGreaterThanOrEqual(fabs(tester.mapView.direction - startAngle),
- 20,
- @"rotating map should change angle");
-}
-
-- (void)testRotateCounterclockwise {
- CLLocationDirection startAngle = tester.mapView.direction;
-
- XCTAssertNotEqual(startAngle,
- -45,
- @"start angle must not be destination angle");
-
- [tester.mapView twoFingerRotateAtPoint:tester.mapView.center angle:-45];
-
- XCTAssertGreaterThanOrEqual(fabs(startAngle - tester.mapView.direction),
- 20,
- @"rotating map should change angle");
- XCTAssertGreaterThan(tester.mapView.camera.heading, 0, @"camera should not go negative");
-}
-
-- (void)testRotateDisabled {
- tester.mapView.rotateEnabled = NO;
- CLLocationDirection startAngle = tester.mapView.direction;
-
- XCTAssertNotEqual(startAngle,
- 45,
- @"start angle must not be destination angle");
-
- [tester.mapView twoFingerRotateAtPoint:tester.mapView.center angle:45];
-
- XCTAssertEqualWithAccuracy(tester.mapView.direction,
- startAngle,
- 0.005,
- @"disabling rotation show disallow rotation gestures");
-}
-
-- (void)testZoomSet {
- double newZoom = 11.65;
-
- XCTAssertNotEqual(tester.mapView.zoomLevel,
- newZoom,
- @"initial setup should have differing zoom");
-
- tester.mapView.zoomLevel = newZoom;
-
- XCTAssertEqualWithAccuracy(tester.mapView.zoomLevel,
- newZoom,
- 0.01,
- @"setting zoom should take effect");
-}
-
-- (void)testCameraDebouncing {
- MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:CLLocationCoordinate2DMake(45, -122)
- fromDistance:100
- pitch:30
- heading:45];
- tester.mapView.camera = camera;
- XCTAssertEqualObjects(tester.mapView.camera, camera);
-
- [tester.mapView setCamera:camera withDuration:10 animationTimingFunction:nil completionHandler:^{
- XCTAssert(NO, @"Camera animation should not be canceled by redundantly setting the camera to the current camera.");
- }];
- XCTAssertEqualObjects(tester.mapView.camera, camera);
-
- tester.mapView.camera = camera;
- XCTAssertEqualObjects(tester.mapView.camera, camera);
-}
-
-- (void)testMarkerSelection {
- CGPoint point = CGPointMake(100, 100);
- MGLPointAnnotation *marker = [MGLPointAnnotation new];
- marker.coordinate = [tester.mapView convertPoint:point toCoordinateFromView:tester.mapView];
- marker.title = @"test"; // title required for callout
- [tester.mapView addAnnotation:marker];
-
- XCTAssertEqual(tester.mapView.selectedAnnotations.count, 0);
-
- [tester.mapView selectAnnotation:marker animated:NO];
- XCTAssertEqualObjects(tester.mapView.selectedAnnotations.firstObject, marker);
-
- [tester.mapView deselectAnnotation:marker animated:NO];
- XCTAssertEqual(tester.mapView.selectedAnnotations.count, 0);
-}
-
-- (void)testMarkerAddWithoutDelegate {
- XCTAssertFalse([tester.viewController respondsToSelector:@selector(mapView:imageForAnnotation:)]);
-
- MGLPointAnnotation *marker = [MGLPointAnnotation new];
- marker.coordinate = tester.mapView.centerCoordinate;
- [tester.mapView addAnnotation:marker];
-
- [tester.mapView selectAnnotation:marker animated:NO];
- XCTAssertEqualObjects(tester.mapView.selectedAnnotations.firstObject, marker);
- XCTAssertEqual([[tester.mapView subviewsWithClassNamePrefix:@"SM"] count], 0); // no callout for no title
-
- [tester.mapView deselectAnnotation:marker animated:NO];
- marker.title = @"test";
- [tester.mapView selectAnnotation:marker animated:NO];
- XCTAssertEqualObjects(tester.mapView.selectedAnnotations.firstObject, marker);
- XCTAssertGreaterThan([[tester.mapView subviewsWithClassNamePrefix:@"SM"] count], 0);
-}
-
-- (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id<MGLAnnotation>)annotation {
- return YES;
-}
-
-- (void)testTopLayoutGuide {
- CGRect statusBarFrame, navigationBarFrame, compassFrame;
- UINavigationBar *navigationBar = tester.viewController.navigationController.navigationBar;
-
- compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil];
- statusBarFrame = [tester.window convertRect:[[UIApplication sharedApplication] statusBarFrame] toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(compassFrame, statusBarFrame),
- @"compass should not be under status bar");
-
- tester.viewController.navigationController.navigationBarHidden = NO;
- compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil];
- navigationBarFrame = [tester.window convertRect:navigationBar.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(compassFrame, navigationBarFrame),
- @"compass should not be under navigation bar");
-
- [system simulateDeviceRotationToOrientation:UIDeviceOrientationLandscapeLeft];
-
- compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil];
- navigationBarFrame = [tester.window convertRect:navigationBar.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(compassFrame, navigationBarFrame),
- @"rotated device should not have compass under navigation bar");
-
- tester.viewController.navigationController.navigationBarHidden = YES;
- compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil];
- statusBarFrame = [tester.window convertRect:[[UIApplication sharedApplication] statusBarFrame] toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(compassFrame, statusBarFrame),
- @"rotated device should not have compass under status bar");
-}
-
-- (void)testBottomLayoutGuide {
- CGRect logoBugFrame, toolbarFrame, attributionButtonFrame;
- UIView *logoBug = (UIView *)[tester waitForViewWithAccessibilityLabel:@"Mapbox"];
- UIToolbar *toolbar = tester.viewController.navigationController.toolbar;
- UIView *attributionButton = (UIView *)[tester waitForViewWithAccessibilityLabel:@"About this map"];
-
- tester.viewController.navigationController.toolbarHidden = NO;
-
- logoBugFrame = [logoBug.superview convertRect:logoBug.frame toView:nil];
- toolbarFrame = [tester.window convertRect:toolbar.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(logoBugFrame, toolbarFrame),
- @"logo bug should not be under toolbar");
-
- attributionButtonFrame = [attributionButton.superview convertRect:attributionButton.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(attributionButtonFrame, toolbarFrame),
- @"attribution button should not be under toolbar");
-
- [system simulateDeviceRotationToOrientation:UIDeviceOrientationLandscapeRight];
-
- logoBugFrame = [logoBug.superview convertRect:logoBug.frame toView:nil];
- toolbarFrame = [tester.window convertRect:toolbar.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(logoBugFrame, toolbarFrame),
- @"rotated device should not have logo bug under toolbar");
-
- attributionButtonFrame = [attributionButton.superview convertRect:attributionButton.frame toView:nil];
- XCTAssertFalse(CGRectIntersectsRect(attributionButtonFrame, toolbarFrame),
- @"rotated device should not have attribution button under toolbar");
-}
-
-- (void)testInsetMapView {
- [tester.viewController insetMapView];
- [tester waitForAnimationsToFinish];
-
- UIView *logoBug = (UIView *)[tester waitForViewWithAccessibilityLabel:@"Mapbox"];
- UIView *attributionButton = (UIView *)[tester waitForViewWithAccessibilityLabel:@"About this map"];
-
- CGRect mapViewFrame = [tester.mapView.superview convertRect:tester.mapView.frame toView:nil];
-
- CGRect logoBugFrame = [logoBug.superview convertRect:logoBug.frame toView:nil];
- XCTAssertTrue(CGRectIntersectsRect(logoBugFrame, mapViewFrame),
- @"logo bug should lie inside shrunken map view");
-
- CGRect attributionButtonFrame = [attributionButton.superview convertRect:attributionButton.frame toView:nil];
- XCTAssertTrue(CGRectIntersectsRect(attributionButtonFrame, mapViewFrame),
- @"attribution button should lie inside shrunken map view");
-
- CGRect compassFrame = [tester.compass.superview convertRect:tester.compass.frame toView:nil];
- XCTAssertTrue(CGRectIntersectsRect(compassFrame, mapViewFrame),
- @"compass should lie inside shrunken map view");
-}
-
-- (void)testContentInsetsWithTinyMapView {
- [tester.viewController tinyMapView];
- [self keyValueObservingExpectationForObject:tester.mapView keyPath:@"contentInset" handler:^BOOL(id observedObject, NSDictionary *change) {
- XCTAssertEqual(tester.mapView.contentInset.top,
- 0,
- @"map should not have top content inset");
- XCTAssertEqual(tester.mapView.contentInset.bottom,
- 0,
- @"map should not have bottom content inset");
- return YES;
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-
- tester.mapView.frame = CGRectMake(0, 0, tester.mapView.frame.size.width, tester.mapView.frame.size.height);
- [self keyValueObservingExpectationForObject:tester.mapView keyPath:@"contentInset" handler:^BOOL(id observedObject, NSDictionary *change) {
- XCTAssertEqual(tester.mapView.contentInset.top,
- tester.viewController.topLayoutGuide.length,
- @"map should have top content inset equal to the top layout guide");
- return YES;
- }];
- [self waitForExpectationsWithTimeout:2.0 handler:nil];
-}
-
-- (void)testDelegateRegionWillChange {
- __block NSUInteger unanimatedCount;
- __block NSUInteger animatedCount;
- [[NSNotificationCenter defaultCenter] addObserverForName:@"regionWillChangeAnimated"
- object:tester.mapView
- queue:nil
- usingBlock:^(NSNotification *note) {
- if ([note.userInfo[@"animated"] boolValue]) {
- animatedCount++;
- } else {
- unanimatedCount++;
- }
- }];
-
- [tester waitForTimeInterval:1];
-
- unanimatedCount = 0;
- animatedCount = 0;
-
- NSNotification *notification = [system waitForNotificationName:@"regionWillChangeAnimated"
- object:tester.mapView
- whileExecutingBlock:^{
- tester.mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0);
- }];
-
- [tester waitForTimeInterval:1];
-
- XCTAssertEqual([notification.userInfo[@"animated"] boolValue],
- NO,
- @"regionWillChange delegate should not indicate animated change");
- XCTAssertEqual(unanimatedCount,
- 1,
- @"regionWillChange delegate should indicate one unanimated change");
-
- notification = [system waitForNotificationName:@"regionWillChangeAnimated"
- object:tester.mapView
- whileExecutingBlock:^{
- [tester.mapView setCenterCoordinate:CLLocationCoordinate2DMake(45, 100) animated:YES];
- }];
-
- [tester waitForTimeInterval:1];
-
- XCTAssertEqual([notification.userInfo[@"animated"] boolValue],
- YES,
- @"regionWillChange delegate should indicate an animated change");
- XCTAssertEqual(animatedCount,
- 1,
- @"regionWillChange delegate should indicate one animated change");
-
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:@"regionWillChangeAnimated"
- object:tester.mapView];
-}
-
-- (void)mapView:(MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
- [[NSNotificationCenter defaultCenter] postNotificationName:@"regionWillChangeAnimated"
- object:mapView
- userInfo:@{ @"animated" : @(animated) }];
-}
-
-- (void)mapView:(MGLMapView *)mapView regionDidChangeWithReason:(MGLCameraChangeReason)reason animated:(BOOL)animated {
-
- [[NSNotificationCenter defaultCenter] postNotificationName:@"regionDidChangeAnimated"
- object:mapView
- userInfo:@{ @"animated" : @(animated),
- @"reason" : @(reason)
- }];
-}
-
-- (void)testDelegatesStartStopLocatingUser {
- NSNotification *notification = [system waitForNotificationName:@"mapViewWillStartLocatingUser"
- object:tester.mapView
- whileExecutingBlock:^{
- tester.mapView.showsUserLocation = YES;
- [self approveLocationIfNeeded];
- }];
-
- XCTAssertEqualObjects(notification.name,
- @"mapViewWillStartLocatingUser",
- @"mapViewWillStartLocatingUser delegate should receive message");
- XCTAssertNotNil([tester.mapView valueForKeyPath:@"locationManager"],
- "map view location manager should not be nil");
-
- notification = [system waitForNotificationName:@"mapViewDidStopLocatingUser"
- object:tester.mapView
- whileExecutingBlock:^{
- tester.mapView.showsUserLocation = NO;
- }];
-
- XCTAssertEqualObjects(notification.name,
- @"mapViewDidStopLocatingUser",
- @"mapViewDidStopLocatingUser delegate should receive message");
- XCTAssertEqual(tester.mapView.userTrackingMode,
- MGLUserTrackingModeNone,
- @"user tracking mode should be none");
- XCTAssertNil([tester.mapView valueForKeyPath:@"locationManager"],
- "map view location manager should be nil");
-}
-
-- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView {
- [[NSNotificationCenter defaultCenter] postNotificationName:@"mapViewWillStartLocatingUser" object:mapView];
-}
-
-- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView {
- [[NSNotificationCenter defaultCenter] postNotificationName:@"mapViewDidStopLocatingUser" object:mapView];
-}
-
-@end
diff --git a/platform/ios/uitest/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h b/platform/ios/uitest/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h
deleted file mode 100644
index c20a9c2b20..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/NSNotificationCenter+OCMAdditions.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2009-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@class OCObserverMockObject;
-
-
-@interface NSNotificationCenter(OCMAdditions)
-
-- (void)addMockObserver:(OCObserverMockObject *)notificationObserver name:(NSString *)notificationName object:(id)notificationSender;
-
-@end
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMArg.h b/platform/ios/uitest/OCMock/OCMock/OCMArg.h
deleted file mode 100644
index 2b5f9c7a4e..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMArg.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2009-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@interface OCMArg : NSObject
-
-// constraining arguments
-
-+ (id)any;
-+ (SEL)anySelector;
-+ (void *)anyPointer;
-+ (id __autoreleasing *)anyObjectRef;
-+ (id)isNil;
-+ (id)isNotNil;
-+ (id)isEqual:(id)value;
-+ (id)isNotEqual:(id)value;
-+ (id)isKindOfClass:(Class)cls;
-+ (id)checkWithSelector:(SEL)selector onObject:(id)anObject;
-+ (id)checkWithBlock:(BOOL (^)(id obj))block;
-
-// manipulating arguments
-
-+ (id *)setTo:(id)value;
-+ (void *)setToValue:(NSValue *)value;
-
-// internal use only
-
-+ (id)resolveSpecialValues:(NSValue *)value;
-
-@end
-
-#define OCMOCK_ANY [OCMArg any]
-
-#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
- #define OCMOCK_VALUE(variable) \
- ({ __typeof__(variable) __v = (variable); [NSValue value:&__v withObjCType:@encode(__typeof__(__v))]; })
-#else
- #define OCMOCK_VALUE(variable) [NSValue value:&variable withObjCType:@encode(__typeof__(variable))]
-#endif
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h b/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h
deleted file mode 100644
index 25aa8bf497..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2007-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-
-@interface OCMConstraint : NSObject
-
-+ (instancetype)constraint;
-- (BOOL)evaluate:(id)value;
-
-// if you are looking for any, isNil, etc, they have moved to OCMArg
-
-// try to use [OCMArg checkWith...] instead of the constraintWith... methods below
-
-+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject;
-+ (instancetype)constraintWithSelector:(SEL)aSelector onObject:(id)anObject withValue:(id)aValue;
-
-
-@end
-
-@interface OCMAnyConstraint : OCMConstraint
-@end
-
-@interface OCMIsNilConstraint : OCMConstraint
-@end
-
-@interface OCMIsNotNilConstraint : OCMConstraint
-@end
-
-@interface OCMIsNotEqualConstraint : OCMConstraint
-{
- @public
- id testValue;
-}
-
-@end
-
-@interface OCMInvocationConstraint : OCMConstraint
-{
- @public
- NSInvocation *invocation;
-}
-
-@end
-
-@interface OCMBlockConstraint : OCMConstraint
-{
- BOOL (^block)(id);
-}
-
-- (instancetype)initWithConstraintBlock:(BOOL (^)(id))block;
-
-@end
-
-
-#define CONSTRAINT(aSelector) [OCMConstraint constraintWithSelector:aSelector onObject:self]
-#define CONSTRAINTV(aSelector, aValue) [OCMConstraint constraintWithSelector:aSelector onObject:self withValue:(aValue)]
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMLocation.h b/platform/ios/uitest/OCMock/OCMock/OCMLocation.h
deleted file mode 100644
index e510db7aaf..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMLocation.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@interface OCMLocation : NSObject
-{
- id testCase;
- NSString *file;
- NSUInteger line;
-}
-
-+ (instancetype)locationWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine;
-
-- (instancetype)initWithTestCase:(id)aTestCase file:(NSString *)aFile line:(NSUInteger)aLine;
-
-- (id)testCase;
-- (NSString *)file;
-- (NSUInteger)line;
-
-@end
-
-extern OCMLocation *OCMMakeLocation(id testCase, const char *file, int line);
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMMacroState.h b/platform/ios/uitest/OCMock/OCMock/OCMMacroState.h
deleted file mode 100644
index 4b2d635086..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMMacroState.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@class OCMLocation;
-@class OCMRecorder;
-@class OCMStubRecorder;
-@class OCMockObject;
-
-
-@interface OCMMacroState : NSObject
-{
- OCMRecorder *recorder;
-}
-
-+ (void)beginStubMacro;
-+ (OCMStubRecorder *)endStubMacro;
-
-+ (void)beginExpectMacro;
-+ (OCMStubRecorder *)endExpectMacro;
-
-+ (void)beginVerifyMacroAtLocation:(OCMLocation *)aLocation;
-+ (void)endVerifyMacro;
-
-+ (OCMMacroState *)globalState;
-
-- (OCMRecorder *)recorder;
-
-- (void)switchToClassMethod;
-
-@end
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMRecorder.h b/platform/ios/uitest/OCMock/OCMock/OCMRecorder.h
deleted file mode 100644
index f56d2ca4c0..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMRecorder.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@class OCMockObject;
-@class OCMInvocationMatcher;
-
-
-@interface OCMRecorder : NSProxy
-{
- OCMockObject *mockObject;
- OCMInvocationMatcher *invocationMatcher;
-}
-
-- (instancetype)init;
-- (instancetype)initWithMockObject:(OCMockObject *)aMockObject;
-
-- (void)setMockObject:(OCMockObject *)aMockObject;
-
-- (OCMInvocationMatcher *)invocationMatcher;
-
-- (id)classMethod;
-- (id)ignoringNonObjectArgs;
-
-@end
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMStubRecorder.h b/platform/ios/uitest/OCMock/OCMock/OCMStubRecorder.h
deleted file mode 100644
index 890c9ef3bc..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMStubRecorder.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2004-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import "OCMRecorder.h"
-
-
-@interface OCMStubRecorder : OCMRecorder
-
-- (id)andReturn:(id)anObject;
-- (id)andReturnValue:(NSValue *)aValue;
-- (id)andThrow:(NSException *)anException;
-- (id)andPost:(NSNotification *)aNotification;
-- (id)andCall:(SEL)selector onObject:(id)anObject;
-- (id)andDo:(void (^)(NSInvocation *invocation))block;
-- (id)andForwardToRealObject;
-
-@end
-
-
-@interface OCMStubRecorder (Properties)
-
-#define andReturn(aValue) _andReturn(({ __typeof__(aValue) _v = (aValue); [NSValue value:&_v withObjCType:@encode(__typeof__(_v))]; }))
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andReturn)(NSValue *);
-
-#define andThrow(anException) _andThrow(anException)
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andThrow)(NSException *);
-
-#define andPost(aNotification) _andPost(aNotification)
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andPost)(NSNotification *);
-
-#define andCall(anObject, aSelector) _andCall(anObject, aSelector)
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andCall)(id, SEL);
-
-#define andDo(aBlock) _andDo(aBlock)
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andDo)(void (^)(NSInvocation *));
-
-#define andForwardToRealObject() _andForwardToRealObject()
-@property (nonatomic, readonly) OCMStubRecorder *(^ _andForwardToRealObject)(void);
-
-@end
-
-
-
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMock.h b/platform/ios/uitest/OCMock/OCMock/OCMock.h
deleted file mode 100644
index f0083b3507..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMock.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2004-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <OCMock/OCMockObject.h>
-#import <OCMock/OCMRecorder.h>
-#import <OCMock/OCMStubRecorder.h>
-#import <OCMock/OCMConstraint.h>
-#import <OCMock/OCMArg.h>
-#import <OCMock/OCMLocation.h>
-#import <OCMock/OCMMacroState.h>
-#import <OCMock/NSNotificationCenter+OCMAdditions.h>
-
-
-#define OCMClassMock(cls) [OCMockObject niceMockForClass:cls]
-
-#define OCMStrictClassMock(cls) [OCMockObject mockForClass:cls]
-
-#define OCMProtocolMock(protocol) [OCMockObject niceMockForProtocol:protocol]
-
-#define OCMStrictProtocolMock(protocol) [OCMockObject mockForProtocol:protocol]
-
-#define OCMPartialMock(obj) [OCMockObject partialMockForObject:obj]
-
-#define OCMObserverMock() [OCMockObject observerMock]
-
-
-#define OCMStub(invocation) \
-({ \
- _OCMSilenceWarnings( \
- [OCMMacroState beginStubMacro]; \
- invocation; \
- [OCMMacroState endStubMacro]; \
- ); \
-})
-
-#define OCMExpect(invocation) \
-({ \
- _OCMSilenceWarnings( \
- [OCMMacroState beginExpectMacro]; \
- invocation; \
- [OCMMacroState endExpectMacro]; \
- ); \
-})
-
-#define ClassMethod(invocation) \
- _OCMSilenceWarnings( \
- [[OCMMacroState globalState] switchToClassMethod]; \
- invocation; \
- );
-
-
-#define OCMVerifyAll(mock) [mock verifyAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]
-
-#define OCMVerifyAllWithDelay(mock, delay) [mock verifyWithDelay:delay atLocation:OCMMakeLocation(self, __FILE__, __LINE__)]
-
-#define OCMVerify(invocation) \
-({ \
- _OCMSilenceWarnings( \
- [OCMMacroState beginVerifyMacroAtLocation:OCMMakeLocation(self, __FILE__, __LINE__)]; \
- invocation; \
- [OCMMacroState endVerifyMacro]; \
- ); \
-})
-
-#define _OCMSilenceWarnings(macro) \
-({ \
- _Pragma("clang diagnostic push") \
- _Pragma("clang diagnostic ignored \"-Wunused-value\"") \
- macro \
- _Pragma("clang diagnostic pop") \
-})
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMockObject.h b/platform/ios/uitest/OCMock/OCMock/OCMockObject.h
deleted file mode 100644
index 63f2bae2be..0000000000
--- a/platform/ios/uitest/OCMock/OCMock/OCMockObject.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2004-2014 Erik Doernenburg and contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use these files except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- */
-
-#import <Foundation/Foundation.h>
-
-@class OCMLocation;
-@class OCMInvocationStub;
-@class OCMStubRecorder;
-@class OCMInvocationMatcher;
-@class OCMInvocationExpectation;
-
-
-@interface OCMockObject : NSProxy
-{
- BOOL isNice;
- BOOL expectationOrderMatters;
- NSMutableArray *stubs;
- NSMutableArray *expectations;
- NSMutableArray *exceptions;
- NSMutableArray *invocations;
-}
-
-+ (id)mockForClass:(Class)aClass;
-+ (id)mockForProtocol:(Protocol *)aProtocol;
-+ (id)partialMockForObject:(NSObject *)anObject;
-
-+ (id)niceMockForClass:(Class)aClass;
-+ (id)niceMockForProtocol:(Protocol *)aProtocol;
-
-+ (id)observerMock;
-
-- (instancetype)init;
-
-- (void)setExpectationOrderMatters:(BOOL)flag;
-
-- (id)stub;
-- (id)expect;
-- (id)reject;
-
-- (id)verify;
-- (id)verifyAtLocation:(OCMLocation *)location;
-
-- (void)verifyWithDelay:(NSTimeInterval)delay;
-- (void)verifyWithDelay:(NSTimeInterval)delay atLocation:(OCMLocation *)location;
-
-- (void)stopMocking;
-
-// internal use only
-
-- (void)addStub:(OCMInvocationStub *)aStub;
-- (void)addExpectation:(OCMInvocationExpectation *)anExpectation;
-
-- (BOOL)handleInvocation:(NSInvocation *)anInvocation;
-- (void)handleUnRecordedInvocation:(NSInvocation *)anInvocation;
-- (BOOL)handleSelector:(SEL)sel;
-
-- (void)verifyInvocation:(OCMInvocationMatcher *)matcher;
-- (void)verifyInvocation:(OCMInvocationMatcher *)matcher atLocation:(OCMLocation *)location;
-
-@end
-
diff --git a/platform/ios/uitest/OCMock/libOCMock.a b/platform/ios/uitest/OCMock/libOCMock.a
deleted file mode 100644
index 9bb38e21a3..0000000000
--- a/platform/ios/uitest/OCMock/libOCMock.a
+++ /dev/null
Binary files differ
diff --git a/platform/ios/uitest/OHHTTPStubs b/platform/ios/uitest/OHHTTPStubs
deleted file mode 160000
-Subproject 4dc6f36375f78c0b3cfe58d90bb8a4e21df5196
diff --git a/platform/ios/uitest/ios-tests.xcodeproj/project.pbxproj b/platform/ios/uitest/ios-tests.xcodeproj/project.pbxproj
deleted file mode 100644
index 108139e6e3..0000000000
--- a/platform/ios/uitest/ios-tests.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,546 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- objects = {
-
-/* Begin PBXBuildFile section */
- 96567A231B0E84CD00D78776 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96567A221B0E84CD00D78776 /* LaunchScreen.xib */; };
- 96567A311B0E8BB900D78776 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 96567A301B0E8BB900D78776 /* Images.xcassets */; };
- DA180EF21DD1A4DF000A211D /* OHHTTPStubs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA180EF11DD1A4DF000A211D /* OHHTTPStubs.framework */; };
- DA482C801C12582600772FE3 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA482C7F1C12582600772FE3 /* Mapbox.framework */; };
- DA482C811C12582600772FE3 /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DA482C7F1C12582600772FE3 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- DA9C551D1CD9DFCD000A15C6 /* libKIF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9C551B1CD9DFA7000A15C6 /* libKIF.a */; };
- DD043363196DBBD500E6F39D /* MGLTAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */; };
- DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043360196DBBD500E6F39D /* MGLTViewController.m */; };
- DD043366196DBBE000E6F39D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DD043365196DBBE000E6F39D /* main.m */; };
- DD0580E81ACB628200B112C9 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD0580E71ACB628200B112C9 /* IOKit.framework */; };
- DD0E6F841B0190E200DC035A /* libOCMock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DD0E6F701B0190E200DC035A /* libOCMock.a */; };
- DDBD016C196DC4740033959E /* MapViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBD0168196DC4740033959E /* MapViewTests.m */; };
- DDBD016D196DC4740033959E /* KIFTestActor+MapboxGL.m in Sources */ = {isa = PBXBuildFile; fileRef = DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- DDBD0160196DC3D70033959E /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = DD04331B196DB9BC00E6F39D /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = DD043322196DB9BC00E6F39D;
- remoteInfo = "Mapbox GL Tests";
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- DA482C821C12582600772FE3 /* Embed Frameworks */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 10;
- files = (
- DA482C811C12582600772FE3 /* Mapbox.framework in Embed Frameworks */,
- );
- name = "Embed Frameworks";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 3EAB52CE206ACE7E008BFE2D /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-loop-darwin.a"; sourceTree = BUILT_PRODUCTS_DIR; };
- 3EAB52CF206ACE7E008BFE2D /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
- 96567A221B0E84CD00D78776 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = SOURCE_ROOT; };
- 96567A301B0E8BB900D78776 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = SOURCE_ROOT; };
- DA180EF11DD1A4DF000A211D /* OHHTTPStubs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OHHTTPStubs.framework; path = "OHHTTPStubs/OHHTTPStubs/build/Debug-iphoneos/OHHTTPStubs.framework"; sourceTree = "<group>"; };
- DA482C7F1C12582600772FE3 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- DA9C551B1CD9DFA7000A15C6 /* libKIF.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libKIF.a; path = "../../../build/ios/Build/Products/Debug-iphonesimulator/libKIF.a"; sourceTree = "<group>"; };
- DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL Tests.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTAppDelegate.m; sourceTree = SOURCE_ROOT; };
- DD043360196DBBD500E6F39D /* MGLTViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLTViewController.m; sourceTree = SOURCE_ROOT; };
- DD043361196DBBD500E6F39D /* MGLTViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTViewController.h; sourceTree = SOURCE_ROOT; };
- DD043362196DBBD500E6F39D /* MGLTAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTAppDelegate.h; sourceTree = SOURCE_ROOT; };
- DD043365196DBBE000E6F39D /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; };
- DD043367196DBCC200E6F39D /* App-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = SOURCE_ROOT; };
- DD0580E71ACB628200B112C9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
- DD0E6F701B0190E200DC035A /* libOCMock.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libOCMock.a; path = OCMock/libOCMock.a; sourceTree = SOURCE_ROOT; };
- DD0E6F721B0190E200DC035A /* NSNotificationCenter+OCMAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+OCMAdditions.h"; sourceTree = "<group>"; };
- DD0E6F731B0190E200DC035A /* OCMArg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMArg.h; sourceTree = "<group>"; };
- DD0E6F741B0190E200DC035A /* OCMConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMConstraint.h; sourceTree = "<group>"; };
- DD0E6F751B0190E200DC035A /* OCMLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMLocation.h; sourceTree = "<group>"; };
- DD0E6F761B0190E200DC035A /* OCMMacroState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMMacroState.h; sourceTree = "<group>"; };
- DD0E6F771B0190E200DC035A /* OCMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMock.h; sourceTree = "<group>"; };
- DD0E6F781B0190E200DC035A /* OCMockObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMockObject.h; sourceTree = "<group>"; };
- DD0E6F791B0190E200DC035A /* OCMRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMRecorder.h; sourceTree = "<group>"; };
- DD0E6F7A1B0190E200DC035A /* OCMStubRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMStubRecorder.h; sourceTree = "<group>"; };
- DDBD0152196DC3D70033959E /* Test Bundle.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Test Bundle.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
- DDBD0165196DC4560033959E /* Bundle-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Bundle-Info.plist"; sourceTree = SOURCE_ROOT; };
- DDBD0168196DC4740033959E /* MapViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MapViewTests.m; sourceTree = SOURCE_ROOT; };
- DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KIFTestActor+MapboxGL.m"; sourceTree = SOURCE_ROOT; };
- DDBD016B196DC4740033959E /* KIFTestActor+MapboxGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KIFTestActor+MapboxGL.h"; sourceTree = SOURCE_ROOT; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- DD043320196DB9BC00E6F39D /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- DA482C801C12582600772FE3 /* Mapbox.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- DDBD014F196DC3D70033959E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- DA180EF21DD1A4DF000A211D /* OHHTTPStubs.framework in Frameworks */,
- DD0580E81ACB628200B112C9 /* IOKit.framework in Frameworks */,
- DA9C551D1CD9DFCD000A15C6 /* libKIF.a in Frameworks */,
- DD0E6F841B0190E200DC035A /* libOCMock.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- DD04331A196DB9BC00E6F39D = {
- isa = PBXGroup;
- children = (
- DD04332C196DB9BC00E6F39D /* App */,
- DDBD0139196DC38D0033959E /* Tests */,
- DD043325196DB9BC00E6F39D /* Frameworks */,
- DD043324196DB9BC00E6F39D /* Products */,
- );
- sourceTree = "<group>";
- };
- DD043324196DB9BC00E6F39D /* Products */ = {
- isa = PBXGroup;
- children = (
- DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */,
- DDBD0152196DC3D70033959E /* Test Bundle.xctest */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- DD043325196DB9BC00E6F39D /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 3EAB52CF206ACE7E008BFE2D /* OpenGLES.framework */,
- 3EAB52CE206ACE7E008BFE2D /* libmbgl-loop-darwin.a */,
- DA180EF11DD1A4DF000A211D /* OHHTTPStubs.framework */,
- DA9C551B1CD9DFA7000A15C6 /* libKIF.a */,
- DA482C7F1C12582600772FE3 /* Mapbox.framework */,
- DD0580E71ACB628200B112C9 /* IOKit.framework */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- DD04332C196DB9BC00E6F39D /* App */ = {
- isa = PBXGroup;
- children = (
- DD043362196DBBD500E6F39D /* MGLTAppDelegate.h */,
- DD04335F196DBBD500E6F39D /* MGLTAppDelegate.m */,
- DD043361196DBBD500E6F39D /* MGLTViewController.h */,
- DD043360196DBBD500E6F39D /* MGLTViewController.m */,
- DD04332D196DB9BC00E6F39D /* Supporting Files */,
- );
- name = App;
- path = "Mapbox GL Tests";
- sourceTree = "<group>";
- };
- DD04332D196DB9BC00E6F39D /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 96567A301B0E8BB900D78776 /* Images.xcassets */,
- DD043367196DBCC200E6F39D /* App-Info.plist */,
- DD043365196DBBE000E6F39D /* main.m */,
- 96567A221B0E84CD00D78776 /* LaunchScreen.xib */,
- );
- name = "Supporting Files";
- sourceTree = "<group>";
- };
- DD0E6F6B1B01906600DC035A /* OCMock */ = {
- isa = PBXGroup;
- children = (
- DD0E6F701B0190E200DC035A /* libOCMock.a */,
- DD0E6F711B0190E200DC035A /* OCMock */,
- );
- name = OCMock;
- sourceTree = "<group>";
- };
- DD0E6F711B0190E200DC035A /* OCMock */ = {
- isa = PBXGroup;
- children = (
- DD0E6F721B0190E200DC035A /* NSNotificationCenter+OCMAdditions.h */,
- DD0E6F731B0190E200DC035A /* OCMArg.h */,
- DD0E6F741B0190E200DC035A /* OCMConstraint.h */,
- DD0E6F751B0190E200DC035A /* OCMLocation.h */,
- DD0E6F761B0190E200DC035A /* OCMMacroState.h */,
- DD0E6F771B0190E200DC035A /* OCMock.h */,
- DD0E6F781B0190E200DC035A /* OCMockObject.h */,
- DD0E6F791B0190E200DC035A /* OCMRecorder.h */,
- DD0E6F7A1B0190E200DC035A /* OCMStubRecorder.h */,
- );
- name = OCMock;
- path = OCMock/OCMock;
- sourceTree = SOURCE_ROOT;
- };
- DDBD0139196DC38D0033959E /* Tests */ = {
- isa = PBXGroup;
- children = (
- DDBD016B196DC4740033959E /* KIFTestActor+MapboxGL.h */,
- DDBD016A196DC4740033959E /* KIFTestActor+MapboxGL.m */,
- DDBD0168196DC4740033959E /* MapViewTests.m */,
- DDBD0167196DC46B0033959E /* Supporting Files */,
- DD0E6F6B1B01906600DC035A /* OCMock */,
- );
- name = Tests;
- path = "Mapbox GL Tests";
- sourceTree = "<group>";
- };
- DDBD0167196DC46B0033959E /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- DDBD0165196DC4560033959E /* Bundle-Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- DD043322196DB9BC00E6F39D /* Mapbox GL Tests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = DD043358196DB9BC00E6F39D /* Build configuration list for PBXNativeTarget "Mapbox GL Tests" */;
- buildPhases = (
- DD04331F196DB9BC00E6F39D /* Sources */,
- DD043320196DB9BC00E6F39D /* Frameworks */,
- DD043321196DB9BC00E6F39D /* Resources */,
- DA482C821C12582600772FE3 /* Embed Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "Mapbox GL Tests";
- productName = "Mapbox GL Tests";
- productReference = DD043323196DB9BC00E6F39D /* Mapbox GL Tests.app */;
- productType = "com.apple.product-type.application";
- };
- DDBD0151196DC3D70033959E /* Test Bundle */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = DDBD0162196DC3D70033959E /* Build configuration list for PBXNativeTarget "Test Bundle" */;
- buildPhases = (
- DDBD014E196DC3D70033959E /* Sources */,
- DDBD014F196DC3D70033959E /* Frameworks */,
- DDBD0150196DC3D70033959E /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- DDBD0161196DC3D70033959E /* PBXTargetDependency */,
- );
- name = "Test Bundle";
- productName = "Test Bundle";
- productReference = DDBD0152196DC3D70033959E /* Test Bundle.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- DD04331B196DB9BC00E6F39D /* Project object */ = {
- isa = PBXProject;
- attributes = {
- CLASSPREFIX = MGLT;
- LastUpgradeCheck = 0700;
- ORGANIZATIONNAME = Mapbox;
- TargetAttributes = {
- DDBD0151196DC3D70033959E = {
- TestTargetID = DD043322196DB9BC00E6F39D;
- };
- };
- };
- buildConfigurationList = DD04331E196DB9BC00E6F39D /* Build configuration list for PBXProject "ios-tests" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = DD04331A196DB9BC00E6F39D;
- productRefGroup = DD043324196DB9BC00E6F39D /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- DD043322196DB9BC00E6F39D /* Mapbox GL Tests */,
- DDBD0151196DC3D70033959E /* Test Bundle */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- DD043321196DB9BC00E6F39D /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 96567A311B0E8BB900D78776 /* Images.xcassets in Resources */,
- 96567A231B0E84CD00D78776 /* LaunchScreen.xib in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- DDBD0150196DC3D70033959E /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- DD04331F196DB9BC00E6F39D /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- DD043366196DBBE000E6F39D /* main.m in Sources */,
- DD043363196DBBD500E6F39D /* MGLTAppDelegate.m in Sources */,
- DD043364196DBBD500E6F39D /* MGLTViewController.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- DDBD014E196DC3D70033959E /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- DDBD016D196DC4740033959E /* KIFTestActor+MapboxGL.m in Sources */,
- DDBD016C196DC4740033959E /* MapViewTests.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- DDBD0161196DC3D70033959E /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = DD043322196DB9BC00E6F39D /* Mapbox GL Tests */;
- targetProxy = DDBD0160196DC3D70033959E /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
- DD043356196DB9BC00E6F39D /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- SYMROOT = ../../../build/ios;
- TARGETED_DEVICE_FAMILY = "1,2";
- };
- name = Debug;
- };
- DD043357196DB9BC00E6F39D /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = YES;
- ENABLE_NS_ASSERTIONS = NO;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_SYMBOLS_PRIVATE_EXTERN = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- SDKROOT = iphoneos;
- SYMROOT = ../../../build/ios;
- TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
- DD043359196DB9BC00E6F39D /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- FRAMEWORK_SEARCH_PATHS = "$(inherited)";
- HEADER_SEARCH_PATHS = "";
- INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- OTHER_LDFLAGS = "";
- PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TARGETED_DEVICE_FAMILY = "1,2";
- WRAPPER_EXTENSION = app;
- };
- name = Debug;
- };
- DD04335A196DB9BC00E6F39D /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- FRAMEWORK_SEARCH_PATHS = "$(inherited)";
- HEADER_SEARCH_PATHS = "";
- INFOPLIST_FILE = "$(SRCROOT)/App-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
- OTHER_LDFLAGS = "";
- PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TARGETED_DEVICE_FAMILY = "1,2";
- WRAPPER_EXTENSION = app;
- };
- name = Release;
- };
- DDBD0163196DC3D70033959E /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Mapbox GL Tests.app/Mapbox GL Tests";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/OHHTTPStubs/OHHTTPStubs/build/Debug-iphoneos",
- );
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- "KIF_XCTEST=1",
- );
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- OCMock,
- OHHTTPStubs/OHHTTPStubs/Sources,
- );
- INFOPLIST_FILE = "Bundle-Info.plist";
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/OCMock",
- );
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-framework",
- XCTest,
- "-ObjC",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUNDLE_LOADER)";
- WRAPPER_EXTENSION = xctest;
- };
- name = Debug;
- };
- DDBD0164196DC3D70033959E /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Mapbox GL Tests.app/Mapbox GL Tests";
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/OHHTTPStubs/OHHTTPStubs/build/Debug-iphoneos",
- );
- GCC_PREPROCESSOR_DEFINITIONS = "KIF_XCTEST=1";
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- OCMock,
- OHHTTPStubs/OHHTTPStubs/Sources,
- );
- INFOPLIST_FILE = "Bundle-Info.plist";
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/OCMock",
- );
- OTHER_LDFLAGS = (
- "$(inherited)",
- "-framework",
- XCTest,
- "-ObjC",
- );
- PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME)";
- TEST_HOST = "$(BUNDLE_LOADER)";
- WRAPPER_EXTENSION = xctest;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- DD04331E196DB9BC00E6F39D /* Build configuration list for PBXProject "ios-tests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- DD043356196DB9BC00E6F39D /* Debug */,
- DD043357196DB9BC00E6F39D /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- DD043358196DB9BC00E6F39D /* Build configuration list for PBXNativeTarget "Mapbox GL Tests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- DD043359196DB9BC00E6F39D /* Debug */,
- DD04335A196DB9BC00E6F39D /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- DDBD0162196DC3D70033959E /* Build configuration list for PBXNativeTarget "Test Bundle" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- DDBD0163196DC3D70033959E /* Debug */,
- DDBD0164196DC3D70033959E /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = DD04331B196DB9BC00E6F39D /* Project object */;
-}
diff --git a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 4cad7961db..0000000000
--- a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "self:Mapbox GL Tests.xcodeproj">
- </FileRef>
-</Workspace>
diff --git a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout b/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout
deleted file mode 100644
index 68c68a2234..0000000000
--- a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/Mapbox GL Tests.xccheckout
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>IDESourceControlProjectFavoriteDictionaryKey</key>
- <false/>
- <key>IDESourceControlProjectIdentifier</key>
- <string>A9E9DC14-62C7-4C7A-B782-6B24B7657046</string>
- <key>IDESourceControlProjectName</key>
- <string>Mapbox GL Tests</string>
- <key>IDESourceControlProjectOriginsDictionary</key>
- <dict>
- <key>1F4F0A5F-01E4-4945-AE04-F4B1B763C2BF</key>
- <string>ssh://github.com/mapbox/mapbox-gl-cocoa.git</string>
- </dict>
- <key>IDESourceControlProjectPath</key>
- <string>test/Mapbox GL Tests/Mapbox GL Tests.xcodeproj/project.xcworkspace</string>
- <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
- <dict>
- <key>1F4F0A5F-01E4-4945-AE04-F4B1B763C2BF</key>
- <string>../../../..</string>
- </dict>
- <key>IDESourceControlProjectURL</key>
- <string>ssh://github.com/mapbox/mapbox-gl-cocoa.git</string>
- <key>IDESourceControlProjectVersion</key>
- <integer>110</integer>
- <key>IDESourceControlProjectWCCIdentifier</key>
- <string>1F4F0A5F-01E4-4945-AE04-F4B1B763C2BF</string>
- <key>IDESourceControlProjectWCConfigurations</key>
- <array>
- <dict>
- <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
- <string>public.vcs.git</string>
- <key>IDESourceControlWCCIdentifierKey</key>
- <string>1F4F0A5F-01E4-4945-AE04-F4B1B763C2BF</string>
- <key>IDESourceControlWCCName</key>
- <string>mapbox-gl-cocoa</string>
- </dict>
- </array>
-</dict>
-</plist>
diff --git a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout b/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout
deleted file mode 100644
index 33408b6083..0000000000
--- a/platform/ios/uitest/ios-tests.xcodeproj/project.xcworkspace/xcshareddata/ios-tests.xccheckout
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
- <key>IDESourceControlProjectFavoriteDictionaryKey</key>
- <false/>
- <key>IDESourceControlProjectIdentifier</key>
- <string>31F71B93-A6C7-4EE6-B62A-5324738E25FE</string>
- <key>IDESourceControlProjectName</key>
- <string>ios-tests</string>
- <key>IDESourceControlProjectOriginsDictionary</key>
- <dict>
- <key>10265E242415D473A6A613214DB7AC3EE3D43F93</key>
- <string>https://github.com/mapbox/KIF.git</string>
- <key>38C2A0D4F62B675E8C16C8BC1437C7753846C8AC</key>
- <string>https://github.com/AliSoftware/OHHTTPStubs.git</string>
- <key>7E68CB584078A487C0535CC191D3B7551EEE2095</key>
- <string>github.com:mapbox/mapbox-gl-native.git</string>
- </dict>
- <key>IDESourceControlProjectPath</key>
- <string>test/ios/ios-tests.xcodeproj</string>
- <key>IDESourceControlProjectRelativeInstallPathDictionary</key>
- <dict>
- <key>10265E242415D473A6A613214DB7AC3EE3D43F93</key>
- <string>../../../..test/ios/KIF</string>
- <key>38C2A0D4F62B675E8C16C8BC1437C7753846C8AC</key>
- <string>../../../../test/ios/OHHTTPStubs</string>
- <key>7E68CB584078A487C0535CC191D3B7551EEE2095</key>
- <string>../../../..</string>
- </dict>
- <key>IDESourceControlProjectURL</key>
- <string>github.com:mapbox/mapbox-gl-native.git</string>
- <key>IDESourceControlProjectVersion</key>
- <integer>111</integer>
- <key>IDESourceControlProjectWCCIdentifier</key>
- <string>7E68CB584078A487C0535CC191D3B7551EEE2095</string>
- <key>IDESourceControlProjectWCConfigurations</key>
- <array>
- <dict>
- <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
- <string>public.vcs.git</string>
- <key>IDESourceControlWCCIdentifierKey</key>
- <string>7E68CB584078A487C0535CC191D3B7551EEE2095</string>
- <key>IDESourceControlWCCName</key>
- <string>gl-native</string>
- </dict>
- <dict>
- <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
- <string>public.vcs.git</string>
- <key>IDESourceControlWCCIdentifierKey</key>
- <string>10265E242415D473A6A613214DB7AC3EE3D43F93</string>
- <key>IDESourceControlWCCName</key>
- <string>KIF</string>
- </dict>
- <dict>
- <key>IDESourceControlRepositoryExtensionIdentifierKey</key>
- <string>public.vcs.git</string>
- <key>IDESourceControlWCCIdentifierKey</key>
- <string>38C2A0D4F62B675E8C16C8BC1437C7753846C8AC</string>
- <key>IDESourceControlWCCName</key>
- <string>OHHTTPStubs</string>
- </dict>
- </array>
-</dict>
-</plist>
diff --git a/platform/ios/uitest/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme b/platform/ios/uitest/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme
deleted file mode 100644
index 2c8de87a0f..0000000000
--- a/platform/ios/uitest/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0930"
- version = "1.7">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "EABD46791857A0C700A5F081"
- BuildableName = "libKIF.a"
- BlueprintName = "KIF"
- ReferencedContainer = "container:KIF/KIF.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DD043322196DB9BC00E6F39D"
- BuildableName = "Mapbox GL Tests.app"
- BlueprintName = "Mapbox GL Tests"
- ReferencedContainer = "container:ios-tests.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
- <Testables>
- <TestableReference
- skipped = "NO">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DDBD0151196DC3D70033959E"
- BuildableName = "Test Bundle.xctest"
- BlueprintName = "Test Bundle"
- ReferencedContainer = "container:ios-tests.xcodeproj">
- </BuildableReference>
- <SkippedTests>
- <Test
- Identifier = "MapViewTests/testUserTrackingModeFollowWithHeading">
- </Test>
- <Test
- Identifier = "MetricsTests">
- </Test>
- <Test
- Identifier = "MetricsTests/testFlushPostsEvents">
- </Test>
- <Test
- Identifier = "MetricsTests/testPostEventsNetworkRequest">
- </Test>
- <Test
- Identifier = "MetricsTests/testTimerFiresFlush">
- </Test>
- </SkippedTests>
- <LocationScenarioReference
- identifier = "com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier"
- referenceType = "1">
- </LocationScenarioReference>
- </TestableReference>
- </Testables>
- <MacroExpansion>
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DD043322196DB9BC00E6F39D"
- BuildableName = "Mapbox GL Tests.app"
- BlueprintName = "Mapbox GL Tests"
- ReferencedContainer = "container:ios-tests.xcodeproj">
- </BuildableReference>
- </MacroExpansion>
- <AdditionalOptions>
- </AdditionalOptions>
- </TestAction>
- <LaunchAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- debugServiceExtension = "internal"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DD043322196DB9BC00E6F39D"
- BuildableName = "Mapbox GL Tests.app"
- BlueprintName = "Mapbox GL Tests"
- ReferencedContainer = "container:ios-tests.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- buildConfiguration = "Release"
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "DD043322196DB9BC00E6F39D"
- BuildableName = "Mapbox GL Tests.app"
- BlueprintName = "Mapbox GL Tests"
- ReferencedContainer = "container:ios-tests.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/platform/ios/uitest/main.m b/platform/ios/uitest/main.m
deleted file mode 100644
index d79750dcdd..0000000000
--- a/platform/ios/uitest/main.m
+++ /dev/null
@@ -1,9 +0,0 @@
-#import <UIKit/UIKit.h>
-#import "MGLTAppDelegate.h"
-
-int main(int argc, char * argv[])
-{
- @autoreleasepool {
- return UIApplicationMain(argc, argv, nil, NSStringFromClass([MGLTAppDelegate class]));
- }
-}
diff --git a/platform/ios/vendor/SMCalloutView/SMCalloutView.m b/platform/ios/vendor/SMCalloutView/SMCalloutView.m
index a0049a3e2d..7f987c3355 100755
--- a/platform/ios/vendor/SMCalloutView/SMCalloutView.m
+++ b/platform/ios/vendor/SMCalloutView/SMCalloutView.m
@@ -62,6 +62,26 @@ NSTimeInterval const kMGLSMCalloutViewRepositionDelayForUIScrollView = 1.0/3.0;
return self;
}
+- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
+ UIView *hitView = [super hitTest:point withEvent:event];
+
+ // If we tapped on our container (i.e. the UIButton), then ask the background
+ // view if the point is "inside". MGLSMCalloutMaskedBackgroundView provides a
+ // custom implementation that checks against the main callout and the down arrow.
+ // This avoids taps in "blank" space being detected
+
+ if (hitView == self.containerView) {
+ // Ideally we'd use the background mask to determine whether a tap point
+ // is valid, but that's overkill in this situation
+ CGPoint backgroundPoint = [self convertPoint:point toView:self.backgroundView];
+ if (![self.backgroundView pointInside:backgroundPoint withEvent:event]) {
+ return nil;
+ }
+ }
+
+ return hitView;
+}
+
- (BOOL)supportsHighlighting {
if (![self.delegate respondsToSelector:@selector(calloutViewClicked:)])
return NO;
@@ -738,6 +758,24 @@ static UIImage *blackArrowImage = nil, *whiteArrowImage = nil, *grayArrowImage =
return layer;
}
+- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
+
+ // Only interested in providing a custom pointInside for touches.
+ if (event.type != UIEventTypeTouches) {
+ return [super pointInside:point withEvent:event];
+ }
+
+ NSArray *views = @[self.containerView, self.arrowView];
+ for (UIView *view in views) {
+ CGPoint viewPoint = [self convertPoint:point toView:view];
+ if (CGRectContainsPoint(view.bounds, viewPoint)) {
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
@end
@implementation MGLSMCalloutBackgroundView
diff --git a/platform/ios/vendor/mapbox-events-ios b/platform/ios/vendor/mapbox-events-ios
-Subproject ac14fe78043eb823f14c7eefacda29aad0642c9
+Subproject 16ad59ad80a1b0d2ffc206f4c62fb7215dcd279
diff --git a/platform/linux/README.md b/platform/linux/README.md
index 8b8ac9d089..a8a4d459ee 100644
--- a/platform/linux/README.md
+++ b/platform/linux/README.md
@@ -6,7 +6,7 @@ We are using Ubuntu for development. While the software should work on other dis
This process gives you a Linux desktop app built on a Linux host system.
-### Build
+### Prerequisites
Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you can also use [Clang 3.5+](http://llvm.org/apt/).
@@ -15,9 +15,6 @@ Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you ca
sudo apt-get install gcc-4.9 g++-4.9
export CXX=g++-4.9
-**Note**: We partially support C++14 because GCC 4.9 does not fully implement the
-final draft of the C++14 standard. More information in [DEVELOPING.md](DEVELOPING.md).
-
Ensure you have git and other build essentials:
sudo apt-get install curl git build-essential zlib1g-dev automake \
@@ -38,6 +35,21 @@ Install glfw3 dependencies:
x11proto-xf86vidmode-dev libxxf86vm-dev \
libxcursor-dev libxinerama-dev
+[Node.js](https://nodejs.org/) 4.2.1 or later is also required.
+
+[ccache](https://ccache.samba.org) is optional, but improves recompilation performance.
+
+## Build
+
+Clone the git repository:
+
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+
+Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+this repository.
+
Set the environment variable `MAPBOX_ACCESS_TOKEN` to your [Mapbox access token](ACCESS_TOKEN.md):
export MAPBOX_ACCESS_TOKEN=MYTOKEN
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index dd5f0af112..53683daef0 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -11,7 +11,22 @@ mason_use(benchmark VERSION 1.2.0)
mason_use(icu VERSION 58.1-min-size)
mason_use(args VERSION 6.2.0 HEADER_ONLY)
-include(cmake/loop-uv.cmake)
+add_library(mbgl-loop-uv STATIC
+ platform/default/async_task.cpp
+ platform/default/run_loop.cpp
+ platform/default/timer.cpp
+)
+
+target_include_directories(mbgl-loop-uv
+ PRIVATE include
+ PRIVATE src
+)
+
+target_link_libraries(mbgl-loop-uv
+ PRIVATE mbgl-core
+)
+
+target_add_mason_package(mbgl-loop-uv PUBLIC libuv)
macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC mesa)
@@ -110,8 +125,6 @@ macro(mbgl_platform_glfw)
PRIVATE mbgl-loop-uv
)
- target_add_mason_package(mbgl-glfw PUBLIC libuv)
-
add_custom_command(
TARGET mbgl-glfw POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
@@ -126,8 +139,6 @@ macro(mbgl_platform_render)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-render PUBLIC libuv)
endmacro()
@@ -136,8 +147,6 @@ macro(mbgl_platform_offline)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-offline PUBLIC libuv)
endmacro()
@@ -160,8 +169,6 @@ macro(mbgl_platform_test)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-test PUBLIC libuv)
endmacro()
@@ -180,8 +187,6 @@ macro(mbgl_platform_benchmark)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-benchmark PUBLIC libuv)
endmacro()
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 6c01d7add5..ce661ec102 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -1,5 +1,21 @@
# Changelog for Mapbox Maps SDK for macOS
+## master
+
+### Packaging
+
+* The minimum deployment target for this SDK is now macOS 10.11.0. ([#11776](https://github.com/mapbox/mapbox-gl-native/pull/11776))
+
+### Style layers
+
+* Added support for aggregate expressions as input values to `MGL_MATCH` expressions. ([#11866](https://github.com/mapbox/mapbox-gl-native/pull/11866))
+
+### Other changes
+
+* Unknown tokens in URLs are now preserved, rather than replaced with an empty string. ([#11787](https://github.com/mapbox/mapbox-gl-native/issues/11787))
+* Adjusted when and how the camera transition update and finish callbacks are called, fixing recursion bugs. ([#11614](https://github.com/mapbox/mapbox-gl-native/pull/11614))
+* Fixed an issue preventing nested key path expressions get parsed accordingly to the spec. ([#11959](https://github.com/mapbox/mapbox-gl-native/pull/11959))
+
## 0.7.1
### Style layers
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index bac5683266..f4d946c527 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -4,24 +4,10 @@ This document explains how to build the Mapbox Maps SDK for macOS from source. I
## Requirements
-The Mapbox Maps SDK for macOS and the macosapp demo application run on macOS 10.10.0 or above.
-
-The Mapbox Maps SDK for macOS requires Xcode 8.0 or above.
+See the "Requirements" section in [INSTALL.md](INSTALL.md).
## Building the SDK
-1. [Install core dependencies](../../INSTALL.md).
-1. Run `make xproj`.
-1. Switch to the “dynamic” or “macosapp” scheme. The former builds just the Cocoa framework, while the latter also builds a Cocoa demo application based on it.
-
-### Packaging builds
-
-Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
-```bash
-[sudo] gem install jazzy
-```
-
Build and package the SDK by using one of the following commands:
* `make xpackage` builds a dynamic framework in the Debug configuration, including debug symbols.
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index c723d3e062..f0fb0278be 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -6,19 +6,41 @@ This document explains how to build a development version of the Mapbox Maps SDK
The Mapbox Maps SDK for macOS requires the macOS 10.10.0 SDK (or above) and Xcode 8.0 (or above). To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
-### Building the SDK from source
-
-To build the SDK from source:
-
-1. [Install core dependencies](../../INSTALL.md).
+Before building, follow these steps to install prerequisites:
+1. Install [Xcode](https://developer.apple.com/xcode/)
+1. Launch Xcode and install any updates
+1. Install [Homebrew](http://brew.sh)
+1. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org):
+ ```
+ brew install node cmake ccache
+ ```
+1. Install [xcpretty](https://github.com/supermarin/xcpretty) (optional, used for prettifying command line builds):
+ ```
+ [sudo] gem install xcpretty
+ ```
1. Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
```
[sudo] gem install jazzy
```
-1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/macos/pkg/` folder.
+### Building the SDK from source
+
+To build the SDK from source:
+
+1. Clone the git repository:
+ ```
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+ ```
+ Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+ but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+ this repository.
+1. Run:
+ ```
+ make xpackage
+ ```
+ This produces a `Mapbox.framework` in the `build/macos/pkg/` folder.
### Installation
diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
index 48e43c63bb..ef2772336d 100644
--- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec
+++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :osx
- m.osx.deployment_target = '10.10'
+ m.osx.deployment_target = '10.11'
m.requires_arc = true
diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec
index 27151ae69d..16b63cb34d 100644
--- a/platform/macos/Mapbox-macOS-SDK.podspec
+++ b/platform/macos/Mapbox-macOS-SDK.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :osx
- m.osx.deployment_target = '10.10'
+ m.osx.deployment_target = '10.11'
m.requires_arc = true
diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m
index 0d780424f9..f7b35d0c83 100644
--- a/platform/macos/app/AppDelegate.m
+++ b/platform/macos/app/AppDelegate.m
@@ -29,7 +29,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfResourcesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -37,7 +37,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfResourcesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesExpected {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfResourcesExpected {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -45,7 +45,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfResourcesExpected;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfBytesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfBytesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -53,7 +53,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfBytesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTilesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfTilesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -61,7 +61,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfTilesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTileBytesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfTileBytesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -157,11 +157,11 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
// mapboxgl://?center=29.95,-90.066667&zoom=14&bearing=45&pitch=30
NSURL *url = [NSURL URLWithString:[event paramDescriptorForKeyword:keyDirectObject].stringValue];
- NS_MUTABLE_DICTIONARY_OF(NSString *, NSString *) *params = [[NSMutableDictionary alloc] init];
+ NSMutableDictionary<NSString *, NSString *> *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url.query componentsSeparatedByString:@"&"]) {
NSArray *parts = [param componentsSeparatedByString:@"="];
if (parts.count >= 2) {
- params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ params[parts[0]] = [parts[1] stringByRemovingPercentEncoding];
}
}
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.h b/platform/macos/app/MGLStyle+MBXAdditions.h
index dcaf42af28..29c2cda867 100644
--- a/platform/macos/app/MGLStyle+MBXAdditions.h
+++ b/platform/macos/app/MGLStyle+MBXAdditions.h
@@ -2,6 +2,6 @@
@interface MGLStyle (MBXAdditions)
-@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *reversedLayers;
+@property (nonatomic, strong) NSArray<__kindof MGLStyleLayer *> *reversedLayers;
@end
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.m b/platform/macos/app/MGLStyle+MBXAdditions.m
index be571d8b30..a0773cc2c0 100644
--- a/platform/macos/app/MGLStyle+MBXAdditions.m
+++ b/platform/macos/app/MGLStyle+MBXAdditions.m
@@ -2,15 +2,15 @@
@implementation MGLStyle (MBXAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingReversedLayers {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingReversedLayers {
return [NSSet setWithObject:@"layers"];
}
-- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+- (NSArray<__kindof MGLStyleLayer *> *)reversedLayers {
return self.layers.reverseObjectEnumerator.allObjects;
}
-- (void)setReversedLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+- (void)setReversedLayers:(NSArray<__kindof MGLStyleLayer *> *)reversedLayers {
self.layers = reversedLayers.reverseObjectEnumerator.allObjects;
}
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index aee14c5c2f..4ee6050565 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -19,7 +19,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
{ .latitude = -13.15589555, .longitude = -74.2178961777998 },
};
-NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotation>) *shapes) {
+NSArray<id <MGLAnnotation>> *MBXFlattenedShapes(NSArray<id <MGLAnnotation>> *shapes) {
NSMutableArray *flattenedShapes = [NSMutableArray arrayWithCapacity:shapes.count];
for (id <MGLAnnotation> shape in shapes) {
NSArray *subshapes;
@@ -346,7 +346,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)toggleStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
+ NSArray<MGLStyleLayer *> *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
BOOL isVisible = layers.firstObject.visible;
[self.undoManager registerUndoWithTarget:self handler:^(MapDocument * _Nonnull target) {
[target toggleStyleLayersAtArrangedObjectIndexes:indices];
@@ -382,7 +382,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self deleteStyleLayersAtArrangedObjectIndexes:indices];
}
-- (void)insertStyleLayers:(NS_ARRAY_OF(MGLStyleLayer *) *)layers atArrangedObjectIndexes:(NSIndexSet *)indices {
+- (void)insertStyleLayers:(NSArray<MGLStyleLayer *> *)layers atArrangedObjectIndexes:(NSIndexSet *)indices {
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self deleteStyleLayersAtArrangedObjectIndexes:indices];
}];
@@ -402,7 +402,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)deleteStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
+ NSArray<MGLStyleLayer *> *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertStyleLayers:layers atArrangedObjectIndexes:indices];
}];
@@ -578,7 +578,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self continueWorldTourWithRemainingAnnotations:annotations];
}
-- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations {
+- (void)continueWorldTourWithRemainingAnnotations:(NSMutableArray<MGLPointAnnotation *> *)annotations {
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld) {
_isTouringWorld = NO;
@@ -1242,7 +1242,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
#pragma mark NSSharingServicePickerDelegate methods
-- (NS_ARRAY_OF(NSSharingService *) *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NS_ARRAY_OF(NSSharingService *) *)proposedServices {
+- (NSArray<NSSharingService *> *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray<NSSharingService *> *)proposedServices {
NSURL *shareURL = self.shareURL;
NSURL *browserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:shareURL];
NSImage *browserIcon = [[NSWorkspace sharedWorkspace] iconForFile:browserURL.path];
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index e929bb55c6..aa3f17eea1 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -6,7 +6,6 @@ mason_use(benchmark VERSION 1.2.0)
mason_use(icu VERSION 58.1-min-size)
mason_use(args VERSION 6.2.0 HEADER_ONLY)
-include(cmake/loop-uv.cmake)
include(cmake/loop-darwin.cmake)
macro(mbgl_platform_core)
@@ -155,7 +154,5 @@ macro(mbgl_platform_benchmark)
endmacro()
macro(mbgl_platform_node)
- target_link_libraries(mbgl-node
- PRIVATE "-Wl,-bind_at_load"
- )
+ # Define macro to enable this target on this platform
endmacro()
diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md
index 8089ae17d1..8ce2df39a4 100644
--- a/platform/macos/docs/doc-README.md
+++ b/platform/macos/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for macOS](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/)
-The Mapbox Maps SDK for macOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, Interface Builder, or AppleScript. The SDK takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for macOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.11.0 and above using Objective-C, Swift, Interface Builder, or AppleScript. The SDK takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
![](img/screenshot.jpg)
diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md
index 97e77673ee..4827124be0 100644
--- a/platform/macos/docs/pod-README.md
+++ b/platform/macos/docs/pod-README.md
@@ -10,7 +10,7 @@ Put interactive, scalable world maps into your native Cocoa application with the
![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/docs/img/screenshot.jpg)
-The Mapbox Maps SDK for macOS is compatible with macOS 10.10.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/).
+The Mapbox Maps SDK for macOS is compatible with macOS 10.11.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/).
## Installation
@@ -37,7 +37,7 @@ After running `carthage update`, you’ll find Mapbox.framework in the Carthage/
Create a [Podfile](https://guides.cocoapods.org/syntax/podfile.html) with the following specification:
```rb
-platform :osx, '10.10'
+platform :osx, '10.11'
target 'TargetNameForYourApp' do
pod 'Mapbox-iOS-SDK', '~> x.y'
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 5b17c61de2..4cb436fdbf 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -1833,7 +1833,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SYMROOT = "$(PROJECT_DIR)/cmake";
@@ -1886,7 +1886,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SYMROOT = "$(PROJECT_DIR)/cmake";
diff --git a/platform/macos/src/MGLMapView+IBAdditions.mm b/platform/macos/src/MGLMapView+IBAdditions.mm
index eada47ef90..cef2863ee6 100644
--- a/platform/macos/src/MGLMapView+IBAdditions.mm
+++ b/platform/macos/src/MGLMapView+IBAdditions.mm
@@ -4,7 +4,7 @@
@implementation MGLMapView (IBAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL__ {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL__ {
return [NSSet setWithObject:@"styleURL"];
}
@@ -23,7 +23,7 @@
self.styleURL = url;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLatitude {
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -45,7 +45,7 @@
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLongitude {
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -67,7 +67,7 @@
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsZooming {
return [NSSet setWithObject:@"zoomEnabled"];
}
@@ -79,7 +79,7 @@
self.zoomEnabled = allowsZooming;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsScrolling {
return [NSSet setWithObject:@"scrollEnabled"];
}
@@ -91,7 +91,7 @@
self.scrollEnabled = allowsScrolling;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsRotating {
return [NSSet setWithObject:@"rotateEnabled"];
}
@@ -103,7 +103,7 @@
self.rotateEnabled = allowsRotating;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsTilting {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsTilting {
return [NSSet setWithObject:@"pitchEnabled"];
}
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index e3de1069a9..824df827ac 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -443,7 +443,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated;
/**
Sets the visible region so that the map displays the specified annotations with
@@ -458,7 +458,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
/**
Returns the camera that best fits the given coordinate bounds.
@@ -621,7 +621,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view, the value of this property is
`nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *annotations;
/**
Adds an annotation to the map view.
@@ -651,7 +651,7 @@ MGL_EXPORT IB_DESIGNABLE
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
*/
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
The complete list of annotations associated with the receiver that are
@@ -661,7 +661,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view or if no annotations associated
with the map view are currently visible, the value of this property is `nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *visibleAnnotations;
/**
Removes an annotation from the map view, deselecting it if it is selected.
@@ -686,7 +686,7 @@ MGL_EXPORT IB_DESIGNABLE
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Returns a reusable annotation image object associated with its identifier.
@@ -712,7 +712,7 @@ MGL_EXPORT IB_DESIGNABLE
no annotations associated with the map view are currently visible in the
rectangle.
*/
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect;
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect;
#pragma mark Managing Annotation Selections
@@ -729,7 +729,7 @@ MGL_EXPORT IB_DESIGNABLE
@note In versions prior to `4.0.0` if the annotation was offscreen it was not
selected.
*/
-@property (nonatomic, copy) NS_ARRAY_OF(id <MGLAnnotation>) *selectedAnnotations;
+@property (nonatomic, copy) NSArray<id <MGLAnnotation>> *selectedAnnotations;
/**
Selects an annotation and displays a callout popover for it.
@@ -791,7 +791,7 @@ MGL_EXPORT IB_DESIGNABLE
overlays are associated with the map view, the value of this property is
empty array.
*/
-@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+@property (nonatomic, readonly, nonnull) NSArray<id <MGLOverlay>> *overlays;
/**
Adds a single overlay to the map.
@@ -811,7 +811,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays;
/**
Removes a single overlay from the map.
@@ -831,7 +831,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays;
#pragma mark Accessing the Underlying Map Data
@@ -847,7 +847,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -866,7 +866,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -928,7 +928,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
/**
Returns an array of rendered map features that intersect with the given
@@ -943,7 +943,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
/**
Returns an array of rendered map features that intersect with the given
@@ -962,7 +962,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1026,7 +1026,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
#pragma mark Converting Geographic Coordinates
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 5b78dcca14..bc9ac1e641 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -149,7 +149,7 @@ public:
@property (nonatomic, readwrite) MGLStyle *style;
/// Mapping from reusable identifiers to annotation images.
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, MGLAnnotationImage *> *annotationImagesByIdentifier;
/// Currently shown popover representing the selected annotation.
@property (nonatomic) NSPopover *calloutForSelectedAnnotation;
@@ -611,7 +611,7 @@ public:
#pragma mark Style
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyle {
return [NSSet setWithObject:@"styleURL"];
}
@@ -965,7 +965,7 @@ public:
#pragma mark Viewport
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCenterCoordinate {
return [NSSet setWithObjects:@"latitude", @"longitude", @"camera", nil];
}
@@ -1015,7 +1015,7 @@ public:
_pendingLongitude = pendingLongitude;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomLevel {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel {
return [NSSet setWithObject:@"camera"];
}
@@ -1083,7 +1083,7 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingDirection {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingDirection {
return [NSSet setWithObject:@"camera"];
}
@@ -1107,7 +1107,7 @@ public:
[self setDirection:_mbglMap->getBearing() + delta animated:animated];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCamera {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCamera {
return [NSSet setWithObjects:@"latitude", @"longitude", @"centerCoordinate", @"zoomLevel", @"direction", nil];
}
@@ -1765,7 +1765,7 @@ public:
#pragma mark Annotations
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (nullable NSArray<id <MGLAnnotation>> *)annotations {
if (_annotationContextsByAnnotationTag.empty()) {
return nil;
}
@@ -1781,12 +1781,12 @@ public:
return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotations
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotations
{
return [self visibleFeaturesInRect:self.bounds];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -1852,7 +1852,7 @@ public:
}
}
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
if (!annotations) {
return;
}
@@ -1987,7 +1987,7 @@ public:
}
}
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
if (!annotations) {
return;
}
@@ -2192,12 +2192,12 @@ public:
[self didChangeValueForKey:@"selectedAnnotations"];
}
-- (NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations {
+- (NSArray<id <MGLAnnotation>> *)selectedAnnotations {
id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
return selectedAnnotation ? @[selectedAnnotation] : @[];
}
-- (void)setSelectedAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations {
+- (void)setSelectedAnnotations:(NSArray<id <MGLAnnotation>> *)selectedAnnotations {
if (!selectedAnnotations.count) {
return;
}
@@ -2338,7 +2338,7 @@ public:
}
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated {
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated {
CGFloat maximumPadding = 100;
CGFloat yPadding = (NSHeight(self.bounds) / 5 <= maximumPadding) ? (NSHeight(self.bounds) / 5) : maximumPadding;
CGFloat xPadding = (NSWidth(self.bounds) / 5 <= maximumPadding) ? (NSWidth(self.bounds) / 5) : maximumPadding;
@@ -2348,7 +2348,7 @@ public:
[self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
if ( ! annotations || ! annotations.count) return;
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
@@ -2547,11 +2547,11 @@ public:
#pragma mark Overlays
-- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (nonnull NSArray<id <MGLOverlay>> *)overlays
{
if (self.annotations == nil) { return @[]; }
- NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+ NSMutableArray<id <MGLOverlay>> *mutableOverlays = [NSMutableArray array];
[self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
@@ -2567,7 +2567,7 @@ public:
[self addOverlays:@[overlay]];
}
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays) {
@@ -2581,7 +2581,7 @@ public:
[self removeOverlays:@[overlay]];
}
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays {
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays {
#if DEBUG
for (id <MGLOverlay> overlay in overlays) {
NSAssert([overlay conformsToProtocol:@protocol(MGLOverlay)], @"Overlay does not conform to MGLOverlay");
@@ -2662,15 +2662,15 @@ public:
#pragma mark Data
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
// Cocoa origin is at the lower-left corner.
mbgl::ScreenCoordinate screenCoordinate = { point.x, NSHeight(self.bounds) - point.y };
@@ -2693,15 +2693,15 @@ public:
return MGLFeaturesFromMBGLFeatures(features);
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
// Cocoa origin is at the lower-left corner.
mbgl::ScreenBox screenBox = {
{ NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
diff --git a/platform/node/DEVELOPING.md b/platform/node/DEVELOPING.md
index b313d75c13..215b06c7bf 100644
--- a/platform/node/DEVELOPING.md
+++ b/platform/node/DEVELOPING.md
@@ -4,11 +4,13 @@ This document explains how to build the [Node.js](https://nodejs.org/) bindings
## Building
-To develop these bindings, you’ll need to build them from source. Building requires [installing all of the basic dependencies needed for Mapbox GL Native](../../INSTALL.md), then running:
+To develop these bindings, you’ll need to build them from source. Building requires the prerequisites listed in either
+the [macOS](../macos/INSTALL.md#requirements) or [Linux](../linux/README.md#prerequisites) install documentation, depending
+on the target platform.
- npm install --build-from-source
+To compile the Node.js bindings and install module dependencies, from the repository root directory, run:
-From the root directory. This will compile the Node.js bindings and install module dependencies.
+ npm install --build-from-source
To recompile just the C++ code while developing, run `make node`.
diff --git a/platform/node/README.md b/platform/node/README.md
index d19b2a9343..ac5bcd7e8d 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -17,7 +17,8 @@ Run:
npm install @mapbox/mapbox-gl-native
```
-Other platforms will fall back to a source compile with `make node`; see INSTALL.md in the repository root directory for prequisites.
+Other platforms will fall back to a source compile with `make node`; see [DEVELOPING.md](DEVELOPING.md) for details on
+building from source.
## Testing
diff --git a/platform/node/index.js b/platform/node/index.js
index 5944a0a27d..6f6b33058a 100644
--- a/platform/node/index.js
+++ b/platform/node/index.js
@@ -2,9 +2,8 @@
// Shim to wrap req.respond while preserving callback-passing API
-var mbgl = require('../../lib/mapbox_gl_native.node');
+var mbgl = require('../../lib/mbgl-node.abi-' + process.versions.modules);
var constructor = mbgl.Map.prototype.constructor;
-var process = require('process');
var Map = function(options) {
if (!(options instanceof Object)) {
diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp
index 27866ccbed..9faa41d8b8 100644
--- a/platform/node/src/node_expression.cpp
+++ b/platform/node/src/node_expression.cpp
@@ -52,7 +52,7 @@ type::Type parseType(v8::Local<v8::Object> type) {
v8::Local<v8::String> Nkey = Nan::New("N").ToLocalChecked();
if (Nan::Has(type, Nkey).FromMaybe(false)) {
- N = Nan::Get(type, Nkey).ToLocalChecked()->ToInt32()->Value();
+ N = Nan::To<v8::Int32>(Nan::Get(type, Nkey).ToLocalChecked()).ToLocalChecked()->Value();
}
return type::Array(itemType, N);
}
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 9b76f0f542..4d89077d64 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -353,6 +353,18 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
return options;
}
+class RenderRequest : public Nan::AsyncResource {
+public:
+ RenderRequest(v8::Local<v8::Function> callback_) : AsyncResource("mbgl:RenderRequest") {
+ callback.Reset(callback_);
+ }
+ ~RenderRequest() {
+ callback.Reset();
+ }
+
+ Nan::Persistent<v8::Function> callback;
+};
+
/**
* Render an image from the currently-loaded style
*
@@ -385,15 +397,16 @@ void NodeMap::Render(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("Style is not loaded");
}
- if (nodeMap->callback) {
+ if (nodeMap->req) {
return Nan::ThrowError("Map is currently rendering an image");
}
try {
auto options = ParseOptions(Nan::To<v8::Object>(info[0]).ToLocalChecked());
- assert(!nodeMap->callback);
+ assert(!nodeMap->req);
assert(!nodeMap->image.data);
- nodeMap->callback = std::make_unique<Nan::Callback>(info[1].As<v8::Function>());
+ nodeMap->req = std::make_unique<RenderRequest>(Nan::To<v8::Function>(info[1]).ToLocalChecked());
+
nodeMap->startRender(std::move(options));
} catch (mbgl::style::conversion::Error& err) {
return Nan::ThrowTypeError(err.message.c_str());
@@ -447,6 +460,12 @@ void NodeMap::startRender(NodeMap::RenderOptions options) {
}
void NodeMap::renderFinished() {
+ if (!req) {
+ // In some situations, the render finishes at the same time as we call cancel. Make sure
+ // we are only finishing a render once.
+ return;
+ }
+
Nan::HandleScope scope;
// We're done with this render call, so we're unrefing so that the loop could close.
@@ -457,14 +476,17 @@ void NodeMap::renderFinished() {
Unref();
// Move the callback and image out of the way so that the callback can start a new render call.
- auto cb = std::move(callback);
+ auto request = std::move(req);
auto img = std::move(image);
- assert(cb);
+ assert(request);
// These have to be empty to be prepared for the next render call.
- assert(!callback);
+ assert(!req);
assert(!image.data);
+ v8::Local<v8::Function> callback = Nan::New(request->callback);
+ v8::Local<v8::Object> target = Nan::New<v8::Object>();
+
if (error) {
std::string errorMessage;
@@ -482,7 +504,7 @@ void NodeMap::renderFinished() {
error = nullptr;
assert(!error);
- cb->Call(1, argv);
+ request->runInAsyncScope(target, callback, 1, argv);
} else if (img.data) {
v8::Local<v8::Object> pixels = Nan::NewBuffer(
reinterpret_cast<char *>(img.data.get()), img.bytes(),
@@ -498,12 +520,12 @@ void NodeMap::renderFinished() {
Nan::Null(),
pixels
};
- cb->Call(2, argv);
+ request->runInAsyncScope(target, callback, 2, argv);
} else {
v8::Local<v8::Value> argv[] = {
Nan::Error("Didn't get an image")
};
- cb->Call(1, argv);
+ request->runInAsyncScope(target, callback, 1, argv);
}
}
@@ -546,7 +568,7 @@ void NodeMap::Cancel(const Nan::FunctionCallbackInfo<v8::Value>& info) {
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
- if (!nodeMap->callback) return Nan::ThrowError("No render in progress");
+ if (!nodeMap->req) return Nan::ThrowError("No render in progress");
try {
nodeMap->cancel();
@@ -1192,7 +1214,7 @@ std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resou
Nan::New<v8::External>(&callback_)
};
- auto instance = Nan::New(NodeRequest::constructor)->NewInstance(2, argv);
+ auto instance = Nan::NewInstance(Nan::New(NodeRequest::constructor), 2, argv).ToLocalChecked();
Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked());
Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(resource.kind));
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index 7fe23ad86a..19df095481 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -25,6 +25,8 @@ class NodeMapObserver : public mbgl::MapObserver {
void onDidFailLoadingMap(std::exception_ptr) override;
};
+class RenderRequest;
+
class NodeMap : public Nan::ObjectWrap,
public mbgl::FileSource {
public:
@@ -84,7 +86,7 @@ public:
std::exception_ptr error;
mbgl::PremultipliedImage image;
- std::unique_ptr<Nan::Callback> callback;
+ std::unique_ptr<RenderRequest> req;
// Async for delivering the notifications of render completion.
uv_async_t *async;
diff --git a/platform/node/src/node_request.cpp b/platform/node/src/node_request.cpp
index de16710f78..8c26d44583 100644
--- a/platform/node/src/node_request.cpp
+++ b/platform/node/src/node_request.cpp
@@ -124,7 +124,8 @@ void NodeRequest::HandleCallback(const Nan::FunctionCallbackInfo<v8::Value>& inf
void NodeRequest::Execute() {
v8::Local<v8::Value> argv[] = { handle() };
- Nan::MakeCallback(Nan::To<v8::Object>(target->handle()->GetInternalField(1)).ToLocalChecked(), "request", 1, argv);
+ Nan::AsyncResource res("mbgl:execute");
+ res.runInAsyncScope(Nan::To<v8::Object>(target->handle()->GetInternalField(1)).ToLocalChecked(), "request", 1, argv);
}
NodeRequest::NodeAsyncRequest::NodeAsyncRequest(NodeRequest* request_) : request(request_) {
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index 7b8eaeb49f..ac00235702 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -14,18 +14,17 @@
"expression-tests/collator/non-object-error": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
"expression-tests/collator/variant-equals-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
"expression-tests/collator/variant-gteq-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
- "expression-tests/is-supported-script/default": "https://github.com/mapbox/mapbox-gl-native/issues/11693",
+ "expression-tests/is-supported-script/default": "This tests RTL text plugin behavior specific to GL JS",
"expression-tests/resolved-locale/basic": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
"expression-tests/to-string/basic": "https://github.com/mapbox/mapbox-gl-native/issues/11719",
- "query-tests/circle-pitch-scale/viewport-inside-align-map": "https://github.com/mapbox/mapbox-gl-native/issues/10615",
- "query-tests/circle-pitch-scale/viewport-inside-align-viewport": "https://github.com/mapbox/mapbox-gl-native/issues/10615",
- "query-tests/edge-cases/box-cutting-antimeridian-z0": "https://github.com/mapbox/mapbox-gl-native/issues/11607",
- "query-tests/edge-cases/null-island": "https://github.com/mapbox/mapbox-gl-native/issues/11607",
"query-tests/geometry/multilinestring": "needs investigation",
"query-tests/geometry/multipolygon": "needs investigation",
"query-tests/geometry/polygon": "needs investigation",
"query-tests/world-wrapping/box": "skip - needs issue",
"query-tests/world-wrapping/point": "skip - needs issue",
+ "query-tests/circle-radius/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "query-tests/feature-state/default": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "query-tests/regressions/mapbox-gl-js#6555": "skip - no querySourceFeatures in mbgl-node; needs issue",
"render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/debug/collision-lines": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
@@ -43,6 +42,9 @@
"render-tests/fill-extrusion-pattern/opacity": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/geojson/inline-linestring-fill": "current behavior is arbitrary",
"render-tests/geojson/inline-polygon-symbol": "behavior needs reconciliation with gl-js",
+ "render-tests/icon-rotate/with-offset": "https://github.com/mapbox/mapbox-gl-native/issues/11872",
+ "render-tests/line-gradient/gradient": "https://github.com/mapbox/mapbox-gl-native/issues/11718",
+ "render-tests/line-gradient/translucent": "https://github.com/mapbox/mapbox-gl-native/issues/11718",
"render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397",
"render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195",
"render-tests/real-world/bangkok": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
@@ -56,6 +58,7 @@
"render-tests/regressions/mapbox-gl-js#5370": "skip - https://github.com/mapbox/mapbox-gl-native/pull/9439",
"render-tests/regressions/mapbox-gl-js#5740": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
"render-tests/regressions/mapbox-gl-js#5982": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
+ "render-tests/regressions/mapbox-gl-js#6655": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
"render-tests/regressions/mapbox-gl-native#7357": "https://github.com/mapbox/mapbox-gl-native/issues/7357",
"render-tests/runtime-styling/image-add-sdf": "https://github.com/mapbox/mapbox-gl-native/issues/9847",
"render-tests/runtime-styling/paint-property-fill-flat-to-extrude": "https://github.com/mapbox/mapbox-gl-native/issues/6745",
@@ -66,6 +69,7 @@
"render-tests/text-pitch-alignment/map-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
"render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
"render-tests/text-pitch-scaling/line-half": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
+ "render-tests/text-rotate/with-offset": "https://github.com/mapbox/mapbox-gl-native/issues/11872",
"render-tests/video/default": "skip - https://github.com/mapbox/mapbox-gl-native/issues/601",
"render-tests/background-color/colorSpace-hcl": "needs issue",
"render-tests/combinations/background-opaque--heatmap-translucent": "https://github.com/mapbox/mapbox-gl-native/issues/10146",
@@ -108,5 +112,8 @@
"render-tests/combinations/fill-translucent--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/line-translucent--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/raster-translucent--fill-extrusion-translucent": "needs investigation",
- "render-tests/combinations/symbol-translucent--fill-extrusion-translucent": "needs investigation"
+ "render-tests/combinations/symbol-translucent--fill-extrusion-translucent": "needs investigation",
+ "render-tests/feature-state/composite-expression": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "render-tests/feature-state/data-expression": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "render-tests/feature-state/vector-source": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue"
}
diff --git a/platform/qt/README.md b/platform/qt/README.md
index 4d2d887828..f083d4b519 100644
--- a/platform/qt/README.md
+++ b/platform/qt/README.md
@@ -1,4 +1,4 @@
-# Mapbox Qt SDK
+# Mapbox Maps SDK for Qt
[![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native)
@@ -9,7 +9,7 @@ available in the Qt SDK since Qt 5.9. Use the [Qt bugtracker](https://bugreports
to the plugin and this GitHub repository for bugs related to Mapbox GL Native and the Qt bindings.
You should build this repository if you want to develop/contribute using the low level Qt C++ bindings or
-want to contribute to the Mapbox GL Native projectusing the Qt port for debugging.
+want to contribute to the Mapbox GL Native project using the Qt port for debugging.
See the Mapbox Qt landing page for more details: https://www.mapbox.com/qt/
@@ -17,9 +17,7 @@ See the Mapbox Qt landing page for more details: https://www.mapbox.com/qt/
#### Linux
-For Linux (tested on Ubuntu) desktop, together with these [build
-instructions](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/linux#build),
-you also need:
+For Linux (tested on Ubuntu) desktop, together with these [build instructions](../linux/README.md), you also need:
```
$ sudo apt-get install qt5-default
@@ -55,8 +53,7 @@ At runtime, you will also need installed:
### Build instructions
-Public API headers
-can be found in the [platform/qt/include](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/qt/include) directory.
+Public API headers can be found in the [platform/qt/include](qt/include) directory.
#### Linux and macOS
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index f6d5473192..390d89915a 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -22,6 +22,13 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings)
setWindowIcon(QIcon(":icon.png"));
}
+MapWindow::~MapWindow()
+{
+ // Make sure we have a valid context so we
+ // can delete the QMapboxGL.
+ makeCurrent();
+}
+
void MapWindow::selfTest()
{
if (m_bearingAnimation) {
diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp
index c484114ec0..6c05f03562 100644
--- a/platform/qt/app/mapwindow.hpp
+++ b/platform/qt/app/mapwindow.hpp
@@ -29,6 +29,7 @@ class MapWindow : public QGLWidget
public:
MapWindow(const QMapboxGLSettings &);
+ ~MapWindow();
void selfTest();
diff --git a/platform/qt/config.qdocconf b/platform/qt/config.qdocconf
index d6f0edbd32..9d3b8a7ef4 100644
--- a/platform/qt/config.qdocconf
+++ b/platform/qt/config.qdocconf
@@ -7,7 +7,7 @@ include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
Cpp.ignoretokens = Q_MAPBOXGL_EXPORT
project = QMapboxGL
-description = Mapbox Qt SDK
+description = Mapbox Maps SDK for Qt
language = Cpp
outputdir = docs
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index 369890343f..1ab04403cf 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -9,10 +9,14 @@
// This header follows the Qt coding style: https://wiki.qt.io/Qt_Coding_Style
-#if defined(QT_BUILD_MAPBOXGL_LIB)
- #define Q_MAPBOXGL_EXPORT Q_DECL_EXPORT
+#if !defined(QT_MAPBOXGL_STATIC)
+# if defined(QT_BUILD_MAPBOXGL_LIB)
+# define Q_MAPBOXGL_EXPORT Q_DECL_EXPORT
+# else
+# define Q_MAPBOXGL_EXPORT Q_DECL_IMPORT
+# endif
#else
- #define Q_MAPBOXGL_EXPORT Q_DECL_IMPORT
+# define Q_MAPBOXGL_EXPORT
#endif
namespace QMapbox {
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 70fe270902..79eb672d1f 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -128,6 +128,13 @@ public:
MapChangeSourceDidChange
};
+ enum MapLoadingFailure {
+ StyleParseFailure,
+ StyleLoadFailure,
+ NotFoundFailure,
+ UnknownFailure
+ };
+
// Determines the orientation of the map.
enum NorthOrientation {
NorthUpwards, // Default
@@ -248,6 +255,7 @@ public slots:
signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
+ void mapLoadingFailed(QMapboxGL::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
void staticRenderFinished(const QString &error);
@@ -259,5 +267,6 @@ private:
};
Q_DECLARE_METATYPE(QMapboxGL::MapChange);
+Q_DECLARE_METATYPE(QMapboxGL::MapLoadingFailure);
#endif // QMAPBOXGL_H
diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp
index 87a9358772..2180f22d07 100644
--- a/platform/qt/src/qmapbox.cpp
+++ b/platform/qt/src/qmapbox.cpp
@@ -24,7 +24,7 @@ namespace QMapbox {
/*!
\namespace QMapbox
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Contains miscellaneous Mapbox bindings used throughout QMapboxGL.
*/
@@ -74,7 +74,7 @@ namespace QMapbox {
/*!
\class QMapbox::Feature
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents \l {https://www.mapbox.com/help/define-features/}{map features}
via its \a type (PointType, LineStringType or PolygonType), \a geometry, \a
@@ -94,7 +94,7 @@ namespace QMapbox {
/*!
\class QMapbox::ShapeAnnotationGeometry
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a shape annotation geometry.
*/
@@ -113,7 +113,7 @@ namespace QMapbox {
/*!
\class QMapbox::SymbolAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
A symbol annotation comprises of its geometry and an icon identifier.
*/
@@ -121,7 +121,7 @@ namespace QMapbox {
/*!
\class QMapbox::LineAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a line annotation object, along with its properties.
@@ -131,7 +131,7 @@ namespace QMapbox {
/*!
\class QMapbox::FillAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a fill annotation object, along with its properties.
@@ -177,7 +177,7 @@ namespace QMapbox {
/*!
\class QMapbox::CustomLayerRenderParameters
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapbox::CustomLayerRenderParameters provides the data passed on each render
pass for a custom layer.
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 2e736c0aa2..8c3355dc09 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -89,15 +89,33 @@ QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
std::shared_ptr<mbgl::DefaultFileSource> sharedDefaultFileSource(
const std::string& cachePath, const std::string& assetRoot, uint64_t maximumCacheSize) {
- static std::weak_ptr<mbgl::DefaultFileSource> weak;
- auto fs = weak.lock();
+ static std::mutex mutex;
+ static std::unordered_map<std::string, std::weak_ptr<mbgl::DefaultFileSource>> fileSources;
- if (!fs) {
- weak = fs = std::make_shared<mbgl::DefaultFileSource>(
- cachePath, assetRoot, maximumCacheSize);
+ std::lock_guard<std::mutex> lock(mutex);
+
+ // Purge entries no longer in use.
+ for (auto it = fileSources.begin(); it != fileSources.end();) {
+ if (!it->second.lock()) {
+ it = fileSources.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Return an existing FileSource if available.
+ auto sharedFileSource = fileSources.find(cachePath);
+ if (sharedFileSource != fileSources.end()) {
+ return sharedFileSource->second.lock();
}
- return fs;
+ // New path, create a new FileSource.
+ auto newFileSource = std::make_shared<mbgl::DefaultFileSource>(
+ cachePath, assetRoot, maximumCacheSize);
+
+ fileSources[cachePath] = newFileSource;
+
+ return newFileSource;
}
// Conversion helper functions.
@@ -136,15 +154,14 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
\class QMapboxGLSettings
\brief The QMapboxGLSettings class stores the initial configuration for QMapboxGL.
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapboxGLSettings is used to configure QMapboxGL at the moment of its creation.
Once created, the QMapboxGLSettings of a QMapboxGL can no longer be changed.
- Cache-related settings are shared between all QMapboxGL instances because different
- maps will share the same cache database file. The first map to configure cache properties
- such as size and path will force the configuration to all newly instantiated QMapboxGL
- objects.
+ Cache-related settings are shared between all QMapboxGL instances using the same cache path.
+ The first map to configure cache properties such as size will force the configuration
+ to all newly instantiated QMapboxGL objects using the same cache in the same process.
\since 4.7
*/
@@ -454,7 +471,7 @@ void QMapboxGLSettings::setResourceTransform(const std::function<std::string(con
\class QMapboxGL
\brief The QMapboxGL class is a Qt wrapper for the Mapbox GL Native engine.
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapboxGL is a Qt friendly version the Mapbox GL Native engine using Qt types
and deep integration with Qt event loop. QMapboxGL relies as much as possible
@@ -518,6 +535,19 @@ void QMapboxGLSettings::setResourceTransform(const std::function<std::string(con
*/
/*!
+ \enum QMapboxGL::MapLoadingFailure
+
+ This enum represents map loading failure type.
+
+ \value StyleParseFailure Failure to parse the style.
+ \value StyleLoadFailure Failure to load the style data.
+ \value NotFoundFailure Failure to obtain style resource file.
+ \value UnknownFailure Unknown map loading failure.
+
+ \sa mapLoadingFailed()
+*/
+
+/*!
\enum QMapboxGL::NorthOrientation
This enum sets the orientation of the north bearing. It will directly affect bearing when
@@ -1636,6 +1666,13 @@ void QMapboxGL::connectionEstablished()
*/
/*!
+ \fn void QMapboxGL::mapLoadingFailed(QMapboxGL::MapLoadingFailure type, const QString &description)
+
+ This signal is emitted when a map loading failure happens. Details of the
+ failures are provided, including its \a type and textual \a description.
+*/
+
+/*!
\fn void QMapboxGL::copyrightsChanged(const QString &copyrightsHtml);
This signal is emitted when the copyrights of the current content of the map
@@ -1672,6 +1709,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
connect(m_mapObserver.get(), SIGNAL(mapChanged(QMapboxGL::MapChange)), q, SIGNAL(mapChanged(QMapboxGL::MapChange)));
+ connect(m_mapObserver.get(), SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)), q, SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)));
connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString)));
// Setup the Map object
diff --git a/platform/qt/src/qmapboxgl_map_observer.cpp b/platform/qt/src/qmapboxgl_map_observer.cpp
index e180ed8fda..44cb8c41d5 100644
--- a/platform/qt/src/qmapboxgl_map_observer.cpp
+++ b/platform/qt/src/qmapboxgl_map_observer.cpp
@@ -2,6 +2,10 @@
#include "qmapboxgl_p.hpp"
+#include <mbgl/util/exception.hpp>
+
+#include <exception>
+
QMapboxGLMapObserver::QMapboxGLMapObserver(QMapboxGLPrivate *d)
: d_ptr(d)
{
@@ -44,9 +48,30 @@ void QMapboxGLMapObserver::onDidFinishLoadingMap()
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
}
-void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr)
+void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr exception)
{
emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
+
+ QMapboxGL::MapLoadingFailure type;
+ QString description;
+
+ try {
+ std::rethrow_exception(exception);
+ } catch (const mbgl::util::StyleParseException& e) {
+ type = QMapboxGL::MapLoadingFailure::StyleParseFailure;
+ description = e.what();
+ } catch (const mbgl::util::StyleLoadException& e) {
+ type = QMapboxGL::MapLoadingFailure::StyleLoadFailure;
+ description = e.what();
+ } catch (const mbgl::util::NotFoundException& e) {
+ type = QMapboxGL::MapLoadingFailure::NotFoundFailure;
+ description = e.what();
+ } catch (const std::exception& e) {
+ type = QMapboxGL::MapLoadingFailure::UnknownFailure;
+ description = e.what();
+ }
+
+ emit mapLoadingFailed(type, description);
}
void QMapboxGLMapObserver::onWillStartRenderingFrame()
@@ -65,7 +90,7 @@ void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMo
void QMapboxGLMapObserver::onWillStartRenderingMap()
{
- emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+ emit mapChanged(QMapboxGL::MapChangeWillStartRenderingMap);
}
void QMapboxGLMapObserver::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
diff --git a/platform/qt/src/qmapboxgl_map_observer.hpp b/platform/qt/src/qmapboxgl_map_observer.hpp
index c9d0581a90..98da5b6add 100644
--- a/platform/qt/src/qmapboxgl_map_observer.hpp
+++ b/platform/qt/src/qmapboxgl_map_observer.hpp
@@ -36,6 +36,7 @@ public:
signals:
void mapChanged(QMapboxGL::MapChange);
+ void mapLoadingFailed(QMapboxGL::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
private:
diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp
index 80efd6a326..351991f881 100644
--- a/platform/qt/src/sqlite3.cpp
+++ b/platform/qt/src/sqlite3.cpp
@@ -24,11 +24,11 @@ namespace mapbox {
namespace sqlite {
// https://www.sqlite.org/rescode.html#ok
-static_assert(mbgl::underlying_type(Exception::OK) == 0, "error");
+static_assert(mbgl::underlying_type(ResultCode::OK) == 0, "error");
// https://www.sqlite.org/rescode.html#cantopen
-static_assert(mbgl::underlying_type(Exception::CANTOPEN) == 14, "error");
+static_assert(mbgl::underlying_type(ResultCode::CantOpen) == 14, "error");
// https://www.sqlite.org/rescode.html#notadb
-static_assert(mbgl::underlying_type(Exception::NOTADB) == 26, "error");
+static_assert(mbgl::underlying_type(ResultCode::NotADB) == 26, "error");
void checkQueryError(const QSqlQuery& query) {
QSqlError lastError = query.lastError();
@@ -52,15 +52,6 @@ void checkDatabaseError(const QSqlDatabase &db) {
}
}
-void checkDatabaseOpenError(const QSqlDatabase &db) {
- // Assume every error when opening the data as CANTOPEN. Qt
- // always returns -1 for `nativeErrorCode()` on database errors.
- QSqlError lastError = db.lastError();
- if (lastError.type() != QSqlError::NoError) {
- throw Exception { Exception::Code::CANTOPEN, "Error opening the database." };
- }
-}
-
namespace {
QString incrementCounter() {
static QAtomicInt count = 0;
@@ -70,32 +61,9 @@ namespace {
class DatabaseImpl {
public:
- DatabaseImpl(const char* filename, int flags)
- : connectionName(QString::number(uint64_t(QThread::currentThread())) + incrementCounter())
+ DatabaseImpl(QString connectionName_)
+ : connectionName(std::move(connectionName_))
{
- if (!QSqlDatabase::drivers().contains("QSQLITE")) {
- throw Exception { Exception::Code::CANTOPEN, "SQLite driver not found." };
- }
-
- assert(!QSqlDatabase::contains(connectionName));
- auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
-
- QString connectOptions = db.connectOptions();
- if (flags & OpenFlag::ReadOnly) {
- if (!connectOptions.isEmpty()) connectOptions.append(';');
- connectOptions.append("QSQLITE_OPEN_READONLY");
- }
- if (flags & OpenFlag::SharedCache) {
- if (!connectOptions.isEmpty()) connectOptions.append(';');
- connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE");
- }
-
- db.setConnectOptions(connectOptions);
- db.setDatabaseName(QString(filename));
-
- if (!db.open()) {
- checkDatabaseOpenError(db);
- }
}
~DatabaseImpl() {
@@ -127,12 +95,51 @@ public:
template <typename T>
using optional = std::experimental::optional<T>;
+mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) {
+ if (!QSqlDatabase::drivers().contains("QSQLITE")) {
+ return Exception { ResultCode::CantOpen, "SQLite driver not found." };
+ }
+
+ QString connectionName = QString::number(uint64_t(QThread::currentThread())) + incrementCounter();
-Database::Database(const std::string& file, int flags)
- : impl(std::make_unique<DatabaseImpl>(file.c_str(), flags)) {
- assert(impl);
+ assert(!QSqlDatabase::contains(connectionName));
+ auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
+
+ QString connectOptions = db.connectOptions();
+ if (flags & OpenFlag::ReadOnly) {
+ if (!connectOptions.isEmpty()) connectOptions.append(';');
+ connectOptions.append("QSQLITE_OPEN_READONLY");
+ }
+ if (flags & OpenFlag::SharedCache) {
+ if (!connectOptions.isEmpty()) connectOptions.append(';');
+ connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE");
+ }
+
+ db.setConnectOptions(connectOptions);
+ db.setDatabaseName(QString(filename.c_str()));
+
+ if (!db.open()) {
+ // Assume every error when opening the data as CANTOPEN. Qt
+ // always returns -1 for `nativeErrorCode()` on database errors.
+ return Exception { ResultCode::CantOpen, "Error opening the database." };
+ }
+
+ return Database(std::make_unique<DatabaseImpl>(connectionName));
}
+Database Database::open(const std::string &filename, int flags) {
+ auto result = tryOpen(filename, flags);
+ if (result.is<Exception>()) {
+ throw result.get<Exception>();
+ } else {
+ return std::move(result.get<Database>());
+ }
+}
+
+Database::Database(std::unique_ptr<DatabaseImpl> impl_)
+ : impl(std::move(impl_))
+{}
+
Database::Database(Database &&other)
: impl(std::move(other.impl)) {
assert(impl);
@@ -165,7 +172,9 @@ void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
}
db.setConnectOptions(connectOptions);
if (!db.open()) {
- checkDatabaseOpenError(db);
+ // Assume every error when opening the data as CANTOPEN. Qt
+ // always returns -1 for `nativeErrorCode()` on database errors.
+ throw Exception { ResultCode::CantOpen, "Error opening the database." };
}
}
@@ -186,74 +195,82 @@ void Database::exec(const std::string &sql) {
}
}
-Statement Database::prepare(const char *query) {
- return Statement(this, query);
-}
-
-Statement::Statement(Database *db, const char *sql)
- : impl(std::make_unique<StatementImpl>(QString(sql), QSqlDatabase::database(db->impl->connectionName))) {
+Statement::Statement(Database& db, const char* sql)
+ : impl(std::make_unique<StatementImpl>(QString(sql),
+ QSqlDatabase::database(db.impl->connectionName))) {
assert(impl);
}
-Statement::Statement(Statement &&other)
- : impl(std::move(other.impl)) {
- assert(impl);
+Statement::~Statement() {
+#ifndef NDEBUG
+ // Crash if we're destructing this object while we know a Query object references this.
+ assert(!used);
+#endif
}
-Statement &Statement::operator=(Statement &&other) {
- assert(impl);
- std::swap(impl, other.impl);
- return *this;
+Query::Query(Statement& stmt_) : stmt(stmt_) {
+ assert(stmt.impl);
+
+#ifndef NDEBUG
+ assert(!stmt.used);
+ stmt.used = true;
+#endif
}
-Statement::~Statement() {
+Query::~Query() {
+ reset();
+ clearBindings();
+
+#ifndef NDEBUG
+ stmt.used = false;
+#endif
}
-template void Statement::bind(int, int64_t);
+template void Query::bind(int, int64_t);
template <typename T>
-void Statement::bind(int offset, T value) {
- assert(impl);
+void Query::bind(int offset, T value) {
+ assert(stmt.impl);
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, QVariant::fromValue<T>(value), QSql::In);
- checkQueryError(impl->query);
+ stmt.impl->query.bindValue(offset - 1, QVariant::fromValue<T>(value), QSql::In);
+ checkQueryError(stmt.impl->query);
}
template <>
-void Statement::bind(int offset, std::nullptr_t) {
- assert(impl);
+void Query::bind(int offset, std::nullptr_t) {
+ assert(stmt.impl);
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, QVariant(QVariant::Invalid), QSql::In);
- checkQueryError(impl->query);
+ stmt.impl->query.bindValue(offset - 1, QVariant(QVariant::Invalid), QSql::In);
+ checkQueryError(stmt.impl->query);
}
template <>
-void Statement::bind(int offset, int32_t value) {
+void Query::bind(int offset, int32_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, bool value) {
+void Query::bind(int offset, bool value) {
bind(offset, static_cast<int>(value));
}
template <>
-void Statement::bind(int offset, int8_t value) {
+void Query::bind(int offset, int8_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, uint8_t value) {
+void Query::bind(int offset, uint8_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, mbgl::Timestamp value) {
+void Query::bind(int offset, mbgl::Timestamp value) {
bind(offset, std::chrono::system_clock::to_time_t(value));
}
template <>
-void Statement::bind(int offset, optional<std::string> value) {
+void Query::bind(int offset, optional<std::string> value) {
if (value) {
bind(offset, *value);
} else {
@@ -262,7 +279,7 @@ void Statement::bind(int offset, optional<std::string> value) {
}
template <>
-void Statement::bind(int offset, optional<mbgl::Timestamp> value) {
+void Query::bind(int offset, optional<mbgl::Timestamp> value) {
if (value) {
bind(offset, *value);
} else {
@@ -270,30 +287,25 @@ void Statement::bind(int offset, optional<mbgl::Timestamp> value) {
}
}
-void Statement::bind(int offset, const char* value, std::size_t length, bool retain) {
- assert(impl);
+void Query::bind(int offset, const char* value, std::size_t length, bool /* retain */) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
// Kept for consistence with the default implementation.
throw std::range_error("value too long");
}
- // Qt SQLite driver treats QByteArray as blob: we need to explicitly
- // declare the variant type as string.
- QVariant text(QVariant::Type::String);
- text.setValue(retain ? QByteArray(value, length) : QByteArray::fromRawData(value, length));
-
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, std::move(text), QSql::In);
+ stmt.impl->query.bindValue(offset - 1, QString(QByteArray(value, length)), QSql::In);
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
-void Statement::bind(int offset, const std::string& value, bool retain) {
+void Query::bind(int offset, const std::string& value, bool retain) {
bind(offset, value.data(), value.size(), retain);
}
-void Statement::bindBlob(int offset, const void* value_, std::size_t length, bool retain) {
- assert(impl);
+void Query::bindBlob(int offset, const void* value_, std::size_t length, bool retain) {
+ assert(stmt.impl);
const char* value = reinterpret_cast<const char*>(value_);
if (length > std::numeric_limits<int>::max()) {
// Kept for consistence with the default implementation.
@@ -301,123 +313,123 @@ void Statement::bindBlob(int offset, const void* value_, std::size_t length, boo
}
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
+ stmt.impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
QByteArray::fromRawData(value, length), QSql::In | QSql::Binary);
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
-void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
bindBlob(offset, value.data(), value.size(), retain);
}
-bool Statement::run() {
- assert(impl);
+bool Query::run() {
+ assert(stmt.impl);
- if (!impl->query.isValid()) {
- if (impl->query.exec()) {
- impl->lastInsertRowId = impl->query.lastInsertId().value<int64_t>();
- impl->changes = impl->query.numRowsAffected();
+ if (!stmt.impl->query.isValid()) {
+ if (stmt.impl->query.exec()) {
+ stmt.impl->lastInsertRowId = stmt.impl->query.lastInsertId().value<int64_t>();
+ stmt.impl->changes = stmt.impl->query.numRowsAffected();
} else {
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
}
- const bool hasNext = impl->query.next();
- if (!hasNext) impl->query.finish();
+ const bool hasNext = stmt.impl->query.next();
+ if (!hasNext) stmt.impl->query.finish();
return hasNext;
}
-template bool Statement::get(int);
-template int Statement::get(int);
-template int64_t Statement::get(int);
-template double Statement::get(int);
+template bool Query::get(int);
+template int Query::get(int);
+template int64_t Query::get(int);
+template double Query::get(int);
-template <typename T> T Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <typename T> T Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
return value.value<T>();
}
-template <> std::vector<uint8_t> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray byteArray = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> std::vector<uint8_t> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray byteArray = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
std::vector<uint8_t> blob(byteArray.begin(), byteArray.end());
return blob;
}
-template <> mbgl::Timestamp Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> mbgl::Timestamp Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
return std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::system_clock::from_time_t(value.value<::time_t>()));
}
-template <> optional<int64_t> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<int64_t> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { value.value<int64_t>() };
}
-template <> optional<double> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<double> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { value.value<double>() };
}
-template <> std::string Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray value = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> std::string Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray value = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
return std::string(value.constData(), value.size());
}
-template <> optional<std::string> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray value = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> optional<std::string> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray value = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { std::string(value.constData(), value.size()) };
}
-template <> optional<mbgl::Timestamp> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<mbgl::Timestamp> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { std::chrono::time_point_cast<mbgl::Seconds>(
std::chrono::system_clock::from_time_t(value.value<::time_t>())) };
}
-void Statement::reset() {
- assert(impl);
- impl->query.finish();
+void Query::reset() {
+ assert(stmt.impl);
+ stmt.impl->query.finish();
}
-void Statement::clearBindings() {
+void Query::clearBindings() {
// no-op
}
-int64_t Statement::lastInsertRowId() const {
- assert(impl);
- return impl->lastInsertRowId;
+int64_t Query::lastInsertRowId() const {
+ assert(stmt.impl);
+ return stmt.impl->lastInsertRowId;
}
-uint64_t Statement::changes() const {
- assert(impl);
- return (impl->changes < 0 ? 0 : impl->changes);
+uint64_t Query::changes() const {
+ assert(stmt.impl);
+ return (stmt.impl->changes < 0 ? 0 : stmt.impl->changes);
}
Transaction::Transaction(Database& db_, Mode mode)
diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js
index b1eeffb8a0..6758793056 100755
--- a/scripts/generate-shaders.js
+++ b/scripts/generate-shaders.js
@@ -7,6 +7,8 @@ const outputPath = 'src/mbgl/shaders';
var shaders = require('../mapbox-gl-js/src/shaders');
+delete shaders.lineGradient;
+
require('./style-code');
writeIfModified(path.join(outputPath, 'preludes.hpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js
index 6ddb787f19..0059863e05 100755
--- a/scripts/generate-style-code.js
+++ b/scripts/generate-style-code.js
@@ -15,10 +15,6 @@ function parseCSSColor(str) {
];
}
-global.isDataDriven = function (property) {
- return property['property-function'] === true;
-};
-
global.isLightProperty = function (property) {
return property['light-property'] === true;
};
@@ -77,30 +73,36 @@ function attributeUniformType(property, type) {
}
global.layoutPropertyType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
- } else {
- return `LayoutProperty<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
+ default:
+ return `LayoutProperty<${evaluatedType(property)}>`;
}
};
global.paintPropertyType = function (property, type) {
- if (isDataDriven(property)) {
- return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
- } else if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') {
- return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
- } else {
- return `PaintProperty<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
+ case 'cross-faded':
+ return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
+ default:
+ return `PaintProperty<${evaluatedType(property)}>`;
}
};
global.propertyValueType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
- } else if (property.name === 'heatmap-color') {
- return `HeatmapColorPropertyValue`;
- } else {
- return `PropertyValue<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ case 'color-ramp':
+ return `HeatmapColorPropertyValue`;
+ default:
+ return `PropertyValue<${evaluatedType(property)}>`;
}
};
diff --git a/scripts/style-spec.js b/scripts/style-spec.js
index 196adc0b32..dd9a127b70 100644
--- a/scripts/style-spec.js
+++ b/scripts/style-spec.js
@@ -1,3 +1,4 @@
var spec = module.exports = require('../mapbox-gl-js/src/style-spec/reference/v8');
// Make temporary modifications here when Native doesn't have all features that JS has.
+delete spec.paint_line['line-gradient'];
diff --git a/src/csscolorparser/csscolorparser.cpp b/src/csscolorparser/csscolorparser.cpp
index 4d1c6a3d65..106dae6cef 100644
--- a/src/csscolorparser/csscolorparser.cpp
+++ b/src/csscolorparser/csscolorparser.cpp
@@ -185,7 +185,6 @@ optional<Color> parse(const std::string& css_str) {
// Convert to lowercase.
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
-
for (const auto& namedColor : namedColors) {
if (str == namedColor.name) {
return { namedColor.color };
@@ -262,8 +261,9 @@ optional<Color> parse(const std::string& css_str) {
}
float h = parseFloat(params[0]) / 360.0f;
- while (h < 0.0f) h++;
- while (h > 1.0f) h--;
+ float i;
+ // Normalize the hue to [0..1[
+ h = std::modf(h, &i);
// NOTE(deanm): According to the CSS spec s/l should only be
// percentages, but we don't bother and let float or percentage.
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index 6bb4783da7..cc69a60ca0 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -24,14 +24,14 @@ FeatureIndex::FeatureIndex(std::unique_ptr<const GeometryTileData> tileData_)
void FeatureIndex::insert(const GeometryCollection& geometries,
std::size_t index,
const std::string& sourceLayerName,
- const std::string& bucketName) {
+ const std::string& bucketLeaderID) {
for (const auto& ring : geometries) {
auto envelope = mapbox::geometry::envelope(ring);
if (envelope.min.x < util::EXTENT &&
envelope.min.y < util::EXTENT &&
envelope.max.x >= 0 &&
envelope.max.y >= 0) {
- grid.insert(IndexedSubfeature(index, sourceLayerName, bucketName, sortIndex++),
+ grid.insert(IndexedSubfeature(index, sourceLayerName, bucketLeaderID, sortIndex++),
{convertPoint<float>(envelope.min), convertPoint<float>(envelope.max)});
}
}
@@ -140,7 +140,7 @@ void FeatureIndex::addFeature(
std::unique_ptr<GeometryTileLayer> sourceLayer;
std::unique_ptr<GeometryTileFeature> geometryTileFeature;
- for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketName)) {
+ for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketLeaderID)) {
const RenderLayer* renderLayer = getRenderLayer(layerID);
if (!renderLayer) {
continue;
@@ -189,8 +189,8 @@ optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(
return translated;
}
-void FeatureIndex::setBucketLayerIDs(const std::string& bucketName, const std::vector<std::string>& layerIDs) {
- bucketLayerIDs[bucketName] = layerIDs;
+void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs) {
+ bucketLayerIDs[bucketLeaderID] = layerIDs;
}
} // namespace mbgl
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index cc91791d36..739c1f282f 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -25,7 +25,7 @@ public:
IndexedSubfeature(std::size_t index_, std::string sourceLayerName_, std::string bucketName_, size_t sortIndex_)
: index(index_)
, sourceLayerName(std::move(sourceLayerName_))
- , bucketName(std::move(bucketName_))
+ , bucketLeaderID(std::move(bucketName_))
, sortIndex(sortIndex_)
, bucketInstanceId(0)
{}
@@ -34,13 +34,13 @@ public:
IndexedSubfeature(const IndexedSubfeature& other, uint32_t bucketInstanceId_)
: index(other.index)
, sourceLayerName(other.sourceLayerName)
- , bucketName(other.bucketName)
+ , bucketLeaderID(other.bucketLeaderID)
, sortIndex(other.sortIndex)
, bucketInstanceId(bucketInstanceId_)
{}
size_t index;
std::string sourceLayerName;
- std::string bucketName;
+ std::string bucketLeaderID;
size_t sortIndex;
// Only used for symbol features
@@ -53,7 +53,7 @@ public:
const GeometryTileData* getData() { return tileData.get(); }
- void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketName);
+ void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketLeaderID);
void query(
std::unordered_map<std::string, std::vector<Feature>>& result,
@@ -74,7 +74,7 @@ public:
const float bearing,
const float pixelsToTileUnits);
- void setBucketLayerIDs(const std::string& bucketName, const std::vector<std::string>& layerIDs);
+ void setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs);
std::unordered_map<std::string, std::vector<Feature>> lookupSymbolFeatures(
const std::vector<IndexedSubfeature>& symbolFeatures,
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index c6352d3e84..4afbe5af1e 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -287,7 +287,7 @@ UniqueTexture Context::createTexture() {
bool Context::supportsVertexArrays() const {
static bool blacklisted = []() {
- const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER)));
Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str());
@@ -318,7 +318,7 @@ bool Context::supportsProgramBinaries() const {
// https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316
// Blacklist Vivante GC4000 due to bugs when linking loaded programs:
// https://github.com/mapbox/mapbox-gl-native/issues/10704
- const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
+ const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER)));
if (renderer.find("Adreno (TM) 3") != std::string::npos
|| renderer.find("Adreno (TM) 4") != std::string::npos
|| renderer.find("Adreno (TM) 5") != std::string::npos
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 950b9ae382..4249ffc24e 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -41,7 +41,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
std::unique_ptr<GeometryTileLayer> sourceLayer_,
ImageDependencies& imageDependencies,
GlyphDependencies& glyphDependencies)
- : bucketName(layers.at(0)->getID()),
+ : bucketLeaderID(layers.at(0)->getID()),
sourceLayer(std::move(sourceLayer_)),
overscaling(parameters.tileID.overscaleFactor()),
zoom(parameters.tileID.overscaledZ),
@@ -293,7 +293,7 @@ void SymbolLayout::addFeature(const std::size_t index,
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketName, symbolInstances.size());
+ IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size());
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
@@ -419,7 +419,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(const bool showCollisionBoxes)
const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
- auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, mayOverlap, std::move(symbolInstances));
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, mayOverlap, bucketLeaderID, std::move(symbolInstances));
for (SymbolInstance &symbolInstance : bucket->symbolInstances) {
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index c93d8f4106..43b577859f 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -43,7 +43,7 @@ public:
std::map<std::string,
std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>> layerPaintProperties;
- const std::string bucketName;
+ const std::string bucketLeaderID;
std::vector<SymbolInstance> symbolInstances;
private:
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index a7beb0f1e2..d81544eed5 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -747,6 +747,11 @@ void Map::Impl::onInvalidate() {
}
void Map::Impl::onUpdate() {
+ // Don't load/render anything in still mode until explicitly requested.
+ if (mode != MapMode::Continuous && !stillImageRequest) {
+ return;
+ }
+
TimePoint timePoint = mode == MapMode::Continuous ? Clock::now() : Clock::time_point::max();
transform.updateTransitions(timePoint);
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 105adf0400..da8e243d91 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -594,13 +594,10 @@ void Transform::startTransition(const CameraOptions& camera,
animation.transitionFrameFn(t);
}
observer.onCameraIsChanging();
+ return false;
} else {
- transitionFinishFn();
- transitionFinishFn = nullptr;
-
- // This callback gets destroyed here,
- // we can only return after this point.
- transitionFrameFn = nullptr;
+ // Indicate that we need to terminate this transition
+ return true;
}
};
@@ -615,7 +612,14 @@ void Transform::startTransition(const CameraOptions& camera,
};
if (!isAnimated) {
- transitionFrameFn(Clock::now());
+ auto update = std::move(transitionFrameFn);
+ auto finish = std::move(transitionFinishFn);
+
+ transitionFrameFn = nullptr;
+ transitionFinishFn = nullptr;
+
+ update(Clock::now());
+ finish();
}
}
@@ -624,8 +628,43 @@ bool Transform::inTransition() const {
}
void Transform::updateTransitions(const TimePoint& now) {
- if (transitionFrameFn) {
- transitionFrameFn(now);
+
+ // Use a temporary function to ensure that the transitionFrameFn lambda is
+ // called only once per update.
+
+ // This addresses the symptoms of https://github.com/mapbox/mapbox-gl-native/issues/11180
+ // where setting a shape source to nil (or similar) in the `onCameraIsChanging`
+ // observer function causes `Map::Impl::onUpdate()` to be called which
+ // in turn calls this function (before the current iteration has completed),
+ // leading to an infinite loop. See https://github.com/mapbox/mapbox-gl-native/issues/5833
+ // for a similar, related, issue.
+ //
+ // By temporarily nulling the `transitionFrameFn` (and then restoring it
+ // after the temporary has been called) we stop this recursion.
+ //
+ // It's important to note that the scope of this change is stop the above
+ // crashes. It doesn't address any potential deeper issue (for example
+ // user error, how often and when transition callbacks are called).
+
+ auto transition = std::move(transitionFrameFn);
+ transitionFrameFn = nullptr;
+
+ if (transition && transition(now)) {
+ // If the transition indicates that it is complete, then we should call
+ // the finish lambda (going via a temporary as above)
+ auto finish = std::move(transitionFinishFn);
+
+ transitionFinishFn = nullptr;
+ transitionFrameFn = nullptr;
+
+ if (finish) {
+ finish();
+ }
+ } else if (!transitionFrameFn) {
+ // We have to check `transitionFrameFn` is nil here, since a new transition
+ // may have been triggered in a user callback (from the transition call
+ // above)
+ transitionFrameFn = std::move(transition);
}
}
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index d429c57661..bff44a2dcd 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -165,7 +165,7 @@ private:
TimePoint transitionStart;
Duration transitionDuration;
- std::function<void(const TimePoint)> transitionFrameFn;
+ std::function<bool(const TimePoint)> transitionFrameFn;
std::function<void()> transitionFinishFn;
};
diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
index 5e2c937091..4fcc761280 100644
--- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
@@ -84,7 +84,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
if (nVertices == 0)
continue;
- auto edgeDistance = 0;
+ std::size_t edgeDistance = 0;
for (uint32_t i = 0; i < nVertices; i++) {
const auto& p1 = ring[i];
@@ -102,7 +102,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
const Point<double> perp = util::unit(util::perp(d1 - d2));
const auto dist = util::dist<int16_t>(d1, d2);
- if (dist > std::numeric_limits<int16_t>::max()) {
+ if (edgeDistance + dist > std::numeric_limits<int16_t>::max()) {
edgeDistance = 0;
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 3d40a1714d..4fe03eb453 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -18,11 +18,13 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo
bool sdfIcons_,
bool iconsNeedLinear_,
bool sortFeaturesByY_,
+ const std::string bucketName_,
const std::vector<SymbolInstance>&& symbolInstances_)
: layout(std::move(layout_)),
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
sortFeaturesByY(sortFeaturesByY_),
+ bucketLeaderID(std::move(bucketName_)),
symbolInstances(std::move(symbolInstances_)),
textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index e52d18372d..e4aaf5ba30 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -47,6 +47,7 @@ public:
bool sdfIcons,
bool iconsNeedLinear,
bool sortFeaturesByY,
+ const std::string bucketLeaderID,
const std::vector<SymbolInstance>&&);
void upload(gl::Context&) override;
@@ -64,6 +65,8 @@ public:
const bool iconsNeedLinear;
const bool sortFeaturesByY;
+ const std::string bucketLeaderID;
+
optional<float> sortedAngle;
bool staticUploaded = false;
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index f22402ac98..2dc5fe7339 100644
--- a/src/mbgl/renderer/layers/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -7,6 +7,7 @@
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/background_program.hpp>
#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/map/transform_state.hpp>
namespace mbgl {
diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp
index 3db02393d2..bfa695586c 100644
--- a/src/mbgl/renderer/render_tile.hpp
+++ b/src/mbgl/renderer/render_tile.hpp
@@ -22,7 +22,7 @@ public:
RenderTile& operator=(const RenderTile&) = delete;
RenderTile& operator=(RenderTile&&) = default;
- const UnwrappedTileID id;
+ UnwrappedTileID id;
Tile& tile;
ClipID clip;
mat4 matrix;
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 359a674a14..ca9e809977 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -85,11 +85,6 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) {
void Renderer::Impl::render(const UpdateParameters& updateParameters) {
if (updateParameters.mode != MapMode::Continuous) {
- // Don't load/render anyting in still mode until explicitly requested.
- if (!updateParameters.stillImageRequest) {
- return;
- }
-
// Reset zoom history state.
zoomHistory.first = true;
}
@@ -385,7 +380,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
for (auto it = order.rbegin(); it != order.rend(); ++it) {
if (it->layer.is<RenderSymbolLayer>()) {
- if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>())) symbolBucketsChanged = true;
+ const float lng = parameters.state.getLatLng().longitude();
+ if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>(), lng)) symbolBucketsChanged = true;
}
}
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index d28e95181b..fd4356ca02 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -90,6 +90,8 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
return;
}
+ handleWrapJump(parameters.transformState.getLatLng().longitude());
+
// Determine the overzooming/underzooming amounts and required tiles.
int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t tileZoom = overscaledZoom;
@@ -238,6 +240,44 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
}
}
+void TilePyramid::handleWrapJump(float lng) {
+ // On top of the regular z/x/y values, TileIDs have a `wrap` value that specify
+ // which cppy of the world the tile belongs to. For example, at `lng: 10` you
+ // might render z/x/y/0 while at `lng: 370` you would render z/x/y/1.
+ //
+ // When lng values get wrapped (going from `lng: 370` to `long: 10`) you expect
+ // to see the same thing on the screen (370 degrees and 10 degrees is the same
+ // place in the world) but all the TileIDs will have different wrap values.
+ //
+ // In order to make this transition seamless, we calculate the rounded difference of
+ // "worlds" between the last frame and the current frame. If the map panned by
+ // a world, then we can assign all the tiles new TileIDs with updated wrap values.
+ // For example, assign z/x/y/1 a new id: z/x/y/0. It is the same tile, just rendered
+ // in a different position.
+ //
+ // This enables us to reuse the tiles at more ideal locations and prevent flickering.
+
+ const float lngDifference = lng - prevLng;
+ const float worldDifference = lngDifference / 360;
+ const int wrapDelta = ::round(worldDifference);
+ prevLng = lng;
+
+ if (wrapDelta) {
+ std::map<OverscaledTileID, std::unique_ptr<Tile>> newTiles;
+ for (auto& tile : tiles) {
+ auto newID = tile.second->id.unwrapTo(tile.second->id.wrap + wrapDelta);
+ tile.second->id = newID;
+ newTiles.emplace(newID, std::move(tile.second));
+ }
+ tiles = std::move(newTiles);
+
+ for (auto& renderTile : renderTiles) {
+ renderTile.id = renderTile.id.unwrapTo(renderTile.id.wrap + wrapDelta);
+ }
+ }
+}
+
+
std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index 0cef9e2c40..4e5f50fd52 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -49,6 +49,8 @@ public:
std::vector<std::reference_wrapper<RenderTile>> getRenderTiles();
Tile* getTile(const OverscaledTileID&);
+ void handleWrapJump(float lng);
+
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
@@ -72,6 +74,8 @@ public:
std::vector<RenderTile> renderTiles;
TileObserver* observer = nullptr;
+
+ float prevLng = 0;
};
} // namespace mbgl
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
index c700295a15..68d2dcc468 100644
--- a/src/mbgl/shaders/line.cpp
+++ b/src/mbgl/shaders/line.cpp
@@ -31,6 +31,7 @@ uniform vec2 u_gl_units_to_pixels;
varying vec2 v_normal;
varying vec2 v_width2;
varying float v_gamma_scale;
+varying highp float v_linesofar;
#ifndef HAS_UNIFORM_u_color
@@ -131,6 +132,8 @@ void main() {
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
+ v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0;
+
vec2 pos = a_pos_normal.xy;
// x is 1 if it's a round cap, 0 otherwise
diff --git a/src/mbgl/storage/resource.cpp b/src/mbgl/storage/resource.cpp
index 207dd2ee69..ba85f87dea 100644
--- a/src/mbgl/storage/resource.cpp
+++ b/src/mbgl/storage/resource.cpp
@@ -79,13 +79,13 @@ Resource Resource::spriteJSON(const std::string& base, float pixelRatio) {
Resource Resource::glyphs(const std::string& urlTemplate, const FontStack& fontStack, const std::pair<uint16_t, uint16_t>& glyphRange) {
return Resource {
Resource::Kind::Glyphs,
- util::replaceTokens(urlTemplate, [&](const std::string& token) {
+ util::replaceTokens(urlTemplate, [&](const std::string& token) -> optional<std::string> {
if (token == "fontstack") {
return util::percentEncode(fontStackToString(fontStack));
} else if (token == "range") {
return util::toString(glyphRange.first) + "-" + util::toString(glyphRange.second);
} else {
- return std::string();
+ return {};
}
})
};
@@ -104,7 +104,7 @@ Resource Resource::tile(const std::string& urlTemplate,
}
return Resource {
Resource::Kind::Tile,
- util::replaceTokens(urlTemplate, [&](const std::string& token) {
+ util::replaceTokens(urlTemplate, [&](const std::string& token) -> optional<std::string> {
if (token == "z") {
return util::toString(z);
} else if (token == "x") {
@@ -123,7 +123,7 @@ Resource Resource::tile(const std::string& urlTemplate,
} else if (token == "ratio") {
return std::string(pixelRatio > 1.0 ? "@2x" : "");
} else {
- return std::string();
+ return {};
}
}),
Resource::TileData {
diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp
index a2c4aa80b3..15ed10a90f 100644
--- a/src/mbgl/style/conversion/tileset.cpp
+++ b/src/mbgl/style/conversion/tileset.cpp
@@ -1,14 +1,11 @@
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/math/clamp.hpp>
namespace mbgl {
namespace style {
namespace conversion {
-bool validateLatitude(const double lat) {
- return lat <= 90 && lat >= -90;
-}
-
optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const {
Tileset result;
@@ -95,16 +92,20 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error
error = { "bounds array must contain numeric longitude and latitude values" };
return {};
}
- if (!validateLatitude(*bottom) || !validateLatitude(*top) || top <= bottom){
- error = { "bounds latitude values must be between -90 and 90 with bottom less than top" };
+
+ bottom = util::clamp(*bottom, -90.0, 90.0);
+ top = util::clamp(*top, -90.0, 90.0);
+ if (top <= bottom){
+ error = { "bounds bottom latitude must be between smaller than top latitude" };
return {};
}
+
if(*left >= *right) {
error = { "bounds left longitude should be less than right longitude" };
return {};
}
- *left = util::max(-180.0, *left);
- *right = util::min(180.0, *right);
+ left = util::max(-180.0, *left);
+ right = util::min(180.0, *right);
result.bounds = LatLngBounds::hull({ *bottom, *left }, { *top, *right });
}
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index 4739d50168..4226756fe4 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -3,6 +3,7 @@
#include <mbgl/style/expression/util.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/math/log2.hpp>
+#include <mbgl/util/i18n.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/platform.hpp>
@@ -472,8 +473,8 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return result;
});
-
- define("round", [](double x) -> Result<double> { return std::round(x); });
+
+ define("round", [](double x) -> Result<double> { return ::round(x); });
define("floor", [](double x) -> Result<double> { return std::floor(x); });
define("ceil", [](double x) -> Result<double> { return std::ceil(x); });
define("abs", [](double x) -> Result<double> { return std::abs(x); });
@@ -488,6 +489,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
define("!", [](bool e) -> Result<bool> { return !e; });
+
+ define("is-supported-script", [](const std::string& x) -> Result<bool> {
+ return util::i18n::isStringInSupportedScript(x);
+ });
define("upcase", [](const std::string& input) -> Result<std::string> {
return platform::uppercase(input);
diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp
index 3d41f0bdd3..59123c9812 100644
--- a/src/mbgl/style/expression/match.cpp
+++ b/src/mbgl/style/expression/match.cpp
@@ -83,6 +83,10 @@ template<> EvaluationResult Match<std::string>::evaluate(const EvaluationContext
return inputValue.error();
}
+ if (!inputValue->is<std::string>()) {
+ return otherwise->evaluate(params);
+ }
+
auto it = branches.find(inputValue->get<std::string>());
if (it != branches.end()) {
return (*it).second->evaluate(params);
@@ -96,7 +100,11 @@ template<> EvaluationResult Match<int64_t>::evaluate(const EvaluationContext& pa
if (!inputValue) {
return inputValue.error();
}
-
+
+ if (!inputValue->is<double>()) {
+ return otherwise->evaluate(params);
+ }
+
const auto numeric = inputValue->get<double>();
int64_t rounded = std::floor(numeric);
if (numeric == rounded) {
@@ -280,7 +288,7 @@ ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) {
branches.push_back(std::make_pair(std::move(labels), std::move(*output)));
}
- auto input = ctx.parse(arrayMember(value, 1), 1, inputType);
+ auto input = ctx.parse(arrayMember(value, 1), 1, {type::Value});
if (!input) {
return ParseResult();
}
@@ -292,6 +300,12 @@ ParseResult parseMatch(const Convertible& value, ParsingContext& ctx) {
assert(inputType && outputType);
+ optional<std::string> err;
+ if ((*input)->getType() != type::Value && (err = type::checkSubtype(*inputType, (*input)->getType()))) {
+ ctx.error(*err, 1);
+ return ParseResult();
+ }
+
return inputType->match(
[&](const type::NumberType&) {
return create<int64_t>(*outputType, std::move(*input), std::move(branches), std::move(*otherwise), ctx);
diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp
index 01a4a02b4e..8df26ca117 100644
--- a/src/mbgl/text/cross_tile_symbol_index.cpp
+++ b/src/mbgl/text/cross_tile_symbol_index.cpp
@@ -61,6 +61,32 @@ void TileLayerIndex::findMatches(std::vector<SymbolInstance>& symbolInstances, c
CrossTileSymbolLayerIndex::CrossTileSymbolLayerIndex() {
}
+/*
+ * Sometimes when a user pans across the antimeridian the longitude value gets wrapped.
+ * To prevent labels from flashing out and in we adjust the tileID values in the indexes
+ * so that they match the new wrapped version of the map.
+ */
+void CrossTileSymbolLayerIndex::handleWrapJump(float newLng) {
+
+ const int wrapDelta = ::round((newLng - lng) / 360);
+ if (wrapDelta != 0) {
+ std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> newIndexes;
+ for (auto& zoomIndex : indexes) {
+ std::map<OverscaledTileID,TileLayerIndex> newZoomIndex;
+ for (auto& index : zoomIndex.second) {
+ // change the tileID's wrap and move its index
+ index.second.coord = index.second.coord.unwrapTo(index.second.coord.wrap + wrapDelta);
+ newZoomIndex.emplace(index.second.coord, std::move(index.second));
+ }
+ newIndexes.emplace(zoomIndex.first, std::move(newZoomIndex));
+ }
+
+ indexes = std::move(newIndexes);
+ }
+
+ lng = newLng;
+}
+
bool CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& tileID, SymbolBucket& bucket, uint32_t& maxCrossTileID) {
const auto& thisZoomIndexes = indexes[tileID.overscaledZ];
auto previousIndex = thisZoomIndexes.find(tileID);
@@ -138,13 +164,15 @@ bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set<uint
CrossTileSymbolIndex::CrossTileSymbolIndex() {}
-bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer) {
+bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer, float lng) {
auto& layerIndex = layerIndexes[symbolLayer.getID()];
bool symbolBucketsChanged = false;
std::unordered_set<uint32_t> currentBucketIDs;
+ layerIndex.handleWrapJump(lng);
+
for (RenderTile& renderTile : symbolLayer.renderTiles) {
if (!renderTile.tile.isRenderable()) {
continue;
@@ -153,6 +181,10 @@ bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer) {
auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only add this layer if it's the "group leader" for the bucket
+ continue;
+ }
if (!symbolBucket.bucketInstanceId) {
symbolBucket.bucketInstanceId = ++maxBucketInstanceId;
diff --git a/src/mbgl/text/cross_tile_symbol_index.hpp b/src/mbgl/text/cross_tile_symbol_index.hpp
index 541c2e3661..051573e1d2 100644
--- a/src/mbgl/text/cross_tile_symbol_index.hpp
+++ b/src/mbgl/text/cross_tile_symbol_index.hpp
@@ -45,18 +45,20 @@ public:
CrossTileSymbolLayerIndex();
bool addBucket(const OverscaledTileID&, SymbolBucket&, uint32_t& maxCrossTileID);
bool removeStaleBuckets(const std::unordered_set<uint32_t>& currentIDs);
+ void handleWrapJump(float newLng);
private:
void removeBucketCrossTileIDs(uint8_t zoom, const TileLayerIndex& removedBucket);
std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> indexes;
std::map<uint8_t, std::set<uint32_t>> usedCrossTileIDs;
+ float lng = 0;
};
class CrossTileSymbolIndex {
public:
CrossTileSymbolIndex();
- bool addLayer(RenderSymbolLayer&);
+ bool addLayer(RenderSymbolLayer&, float lng);
void pruneUnusedLayers(const std::set<std::string>&);
void reset();
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 43e8ff4f93..9883a1f456 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -56,6 +56,11 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri
auto bucket = geometryTile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only place this layer if it's the "group leader" for the bucket
+ continue;
+ }
auto& layout = symbolBucket.layout;
@@ -230,6 +235,10 @@ void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer) {
auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only update opacities this layer if it's the "group leader" for the bucket
+ continue;
+ }
updateBucketOpacities(symbolBucket, seenCrossTileIDs);
}
}
diff --git a/src/mbgl/tile/custom_geometry_tile.cpp b/src/mbgl/tile/custom_geometry_tile.cpp
index 272a1594d4..24f3526184 100644
--- a/src/mbgl/tile/custom_geometry_tile.cpp
+++ b/src/mbgl/tile/custom_geometry_tile.cpp
@@ -38,9 +38,9 @@ void CustomGeometryTile::setTileData(const GeoJSON& geoJSON) {
vtOptions.extent = util::EXTENT;
vtOptions.buffer = ::round(scale * options.buffer);
vtOptions.tolerance = scale * options.tolerance;
- featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON, id.canonical.z, id.canonical.x, id.canonical.y, vtOptions, options.wrap, options.clip).features;
- } else {
- setNecessity(TileNecessity::Optional);
+ featureData = mapbox::geojsonvt::geoJSONToTile(geoJSON,
+ id.canonical.z, id.canonical.x, id.canonical.y,
+ vtOptions, options.wrap, options.clip).features;
}
setData(std::make_unique<GeoJSONTileData>(std::move(featureData)));
}
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index d0490f1009..af122474c2 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -5,7 +5,6 @@
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/feature.hpp>
-#include <mbgl/util/throttler.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/geometry/feature_index.hpp>
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index 23d6864205..2182ec722f 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -113,7 +113,7 @@ public:
void dumpDebugLogs() const;
- const OverscaledTileID id;
+ OverscaledTileID id;
optional<Timestamp> modified;
optional<Timestamp> expires;
diff --git a/src/mbgl/util/compression.cpp b/src/mbgl/util/compression.cpp
index 30e813cbb8..ee3ebe7cae 100644
--- a/src/mbgl/util/compression.cpp
+++ b/src/mbgl/util/compression.cpp
@@ -1,6 +1,6 @@
#include <mbgl/util/compression.hpp>
-#if defined(__QT__) && defined(_WINDOWS)
+#if defined(__QT__) && defined(_WINDOWS) && !defined(__GNUC__)
#include <QtZlib/zlib.h>
#else
#include <zlib.h>
diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp
index 5921edfb14..8048dfe84a 100644
--- a/src/mbgl/util/http_header.cpp
+++ b/src/mbgl/util/http_header.cpp
@@ -8,6 +8,7 @@
#pragma GCC diagnostic ignored "-Wshadow"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#pragma clang diagnostic ignored "-Wtautological-constant-compare"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 1fc13bfb7d..5530796915 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -1,4 +1,5 @@
-#include "i18n.hpp"
+#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/utf.hpp>
#include <algorithm>
#include <map>
@@ -65,7 +66,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F)
// DEFINE_IS_IN_UNICODE_BLOCK(Hanunoo, 0x1720, 0x173F)
// DEFINE_IS_IN_UNICODE_BLOCK(Buhid, 0x1740, 0x175F)
// DEFINE_IS_IN_UNICODE_BLOCK(Tagbanwa, 0x1760, 0x177F)
-// DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF)
+DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Mongolian, 0x1800, 0x18AF)
DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabicsExtended, 0x18B0, 0x18FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Limbu, 0x1900, 0x194F)
@@ -581,6 +582,38 @@ std::u16string verticalizePunctuation(const std::u16string& input) {
char16_t verticalizePunctuation(char16_t chr) {
return verticalPunctuation.count(chr) ? verticalPunctuation.at(chr) : 0;
}
+
+bool charInSupportedScript(char16_t chr) {
+ // This is a rough heuristic: whether we "can render" a script
+ // actually depends on the properties of the font being used
+ // and whether differences from the ideal rendering are considered
+ // semantically significant.
+
+ // Even in Latin script, we "can't render" combinations such as the fi
+ // ligature, but we don't consider that semantically significant.n false;
+ if ((chr >= 0x0900 && chr <= 0x0DFF) ||
+ // Main blocks for Indic scripts and Sinhala
+ (chr >= 0x0F00 && chr <= 0x109F) ||
+ // Main blocks for Tibetan and Myanmar
+ isInKhmer(chr)) {
+ // These blocks cover common scripts that require
+ // complex text shaping, based on unicode script metadata:
+ // http://www.unicode.org/repos/cldr/trunk/common/properties/scriptMetadata.txt
+ // where "Web Rank <= 32" "Shaping Required = YES"
+ return false;
+ }
+ return true;
+}
+
+bool isStringInSupportedScript(const std::string& input) {
+ auto u16string = util::utf8_to_utf16::convert(input);
+ for (char16_t chr : u16string) {
+ if (!charInSupportedScript(chr)) {
+ return false;
+ }
+ }
+ return true;
+}
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
index b3960c743c..a74215a134 100644
--- a/src/mbgl/util/i18n.hpp
+++ b/src/mbgl/util/i18n.hpp
@@ -72,6 +72,8 @@ std::u16string verticalizePunctuation(const std::u16string& input);
@return The character’s specialized vertical form; 0 if not applicable. */
char16_t verticalizePunctuation(char16_t chr);
+
+bool isStringInSupportedScript(const std::string& input);
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp
index 6a6ed7b250..058cd0d202 100644
--- a/src/mbgl/util/io.cpp
+++ b/src/mbgl/util/io.cpp
@@ -20,7 +20,7 @@ void write_file(const std::string &filename, const std::string &data) {
}
std::string read_file(const std::string &filename) {
- std::ifstream file(filename);
+ std::ifstream file(filename, std::ios::binary);
if (file.good()) {
std::stringstream data;
data << file.rdbuf();
@@ -31,7 +31,7 @@ std::string read_file(const std::string &filename) {
}
optional<std::string> readFile(const std::string &filename) {
- std::ifstream file(filename);
+ std::ifstream file(filename, std::ios::binary);
if (file.good()) {
std::stringstream data;
data << file.rdbuf();
diff --git a/src/mbgl/util/throttler.cpp b/src/mbgl/util/throttler.cpp
deleted file mode 100644
index 910810ce2f..0000000000
--- a/src/mbgl/util/throttler.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <mbgl/util/throttler.hpp>
-
-namespace mbgl {
-namespace util {
-
-Throttler::Throttler(Duration frequency_, std::function<void()>&& function_)
- : frequency(frequency_)
- , function(std::move(function_))
- , pendingInvocation(false)
- , lastInvocation(TimePoint::min())
-{}
-
-void Throttler::invoke() {
- if (pendingInvocation) {
- return;
- }
-
- Duration timeToNextInvocation = lastInvocation == TimePoint::min()
- ? Duration::zero()
- : (lastInvocation + frequency) - Clock::now();
-
- if (timeToNextInvocation <= Duration::zero()) {
- lastInvocation = Clock::now();
- function();
- } else {
- pendingInvocation = true;
- timer.start(timeToNextInvocation, Duration::zero(), [this]{
- pendingInvocation = false;
- lastInvocation = Clock::now();
- function();
- });
- }
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/throttler.hpp b/src/mbgl/util/throttler.hpp
deleted file mode 100644
index 175de7ccaf..0000000000
--- a/src/mbgl/util/throttler.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/timer.hpp>
-
-namespace mbgl {
-namespace util {
-
-class Throttler {
-public:
- Throttler(Duration frequency, std::function<void()>&& function);
-
- void invoke();
-private:
- Duration frequency;
- std::function<void()> function;
-
- Timer timer;
- bool pendingInvocation;
- TimePoint lastInvocation;
-};
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 39b562d811..488e6b88ce 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -2,13 +2,18 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/tile_cover_impl.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
#include <functional>
+#include <list>
namespace mbgl {
namespace {
+using ScanLine = const std::function<void(int32_t x0, int32_t x1, int32_t y)>;
+
// Taken from polymaps src/Layer.js
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
struct edge {
@@ -27,8 +32,6 @@ struct edge {
}
};
-using ScanLine = const std::function<void(int32_t x0, int32_t x1, int32_t y)>;
-
// scan-line conversion
static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) {
double y0 = ::fmax(ymin, std::floor(e1.y0));
@@ -147,11 +150,11 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
return tileCover(
- TileCoordinate::fromLatLng(z, bounds.northwest()).p,
- TileCoordinate::fromLatLng(z, bounds.northeast()).p,
- TileCoordinate::fromLatLng(z, bounds.southeast()).p,
- TileCoordinate::fromLatLng(z, bounds.southwest()).p,
- TileCoordinate::fromLatLng(z, bounds.center()).p,
+ Projection::project(bounds.northwest(), z),
+ Projection::project(bounds.northeast(), z),
+ Projection::project(bounds.southeast(), z),
+ Projection::project(bounds.southwest(), z),
+ Projection::project(bounds.center(), z),
z);
}
@@ -169,25 +172,80 @@ std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
z);
}
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>& geometry, int32_t z) {
+ std::vector<UnwrappedTileID> result;
+ TileCover tc(geometry, z, true);
+ while (tc.hasNext()) {
+ result.push_back(*tc.next());
+ };
+
+ return result;
+}
+
// Taken from https://github.com/mapbox/sphericalmercator#xyzbbox-zoom-tms_style-srs
// Computes the projected tiles for the lower left and upper right points of the bounds
// and uses that to compute the tile cover count
-uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom, uint16_t tileSize_){
-
- auto sw = Projection::project(bounds.southwest().wrapped(), zoom, tileSize_);
- auto ne = Projection::project(bounds.northeast().wrapped(), zoom, tileSize_);
-
- auto x1 = floor(sw.x/ tileSize_);
- auto x2 = floor((ne.x - 1) / tileSize_);
- auto y1 = floor(sw.y/ tileSize_);
- auto y2 = floor((ne.y - 1) / tileSize_);
-
- auto minX = ::fmax(std::min(x1, x2), 0);
- auto maxX = std::max(x1, x2);
- auto minY = (std::pow(2, zoom) - 1) - std::max(y1, y2);
- auto maxY = (std::pow(2, zoom) - 1) - ::fmax(std::min(y1, y2), 0);
-
- return (maxX - minX + 1) * (maxY - minY + 1);
+uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom){
+ if (zoom == 0) {
+ return 1;
+ }
+ auto sw = Projection::project(bounds.southwest(), zoom);
+ auto ne = Projection::project(bounds.northeast(), zoom);
+ auto maxTile = std::pow(2.0, zoom);
+ auto x1 = floor(sw.x);
+ auto x2 = ceil(ne.x) - 1;
+ auto y1 = util::clamp(floor(sw.y), 0.0, maxTile - 1);
+ auto y2 = util::clamp(floor(ne.y), 0.0, maxTile - 1);
+
+ auto dx = x1 > x2 ? (maxTile - x1) + x2 : x2 - x1;
+ auto dy = y1 - y2;
+ return (dx + 1) * (dy + 1);
+}
+
+uint64_t tileCount(const Geometry<double>& geometry, uint8_t z) {
+ uint64_t tileCount = 0;
+
+ TileCover tc(geometry, z, true);
+ while (tc.next()) {
+ tileCount++;
+ };
+ return tileCount;
+}
+
+TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
+ LatLngBounds bounds = LatLngBounds::hull(
+ { std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
+ { std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
+
+ if (bounds.isEmpty() ||
+ bounds.south() > util::LATITUDE_MAX ||
+ bounds.north() < -util::LATITUDE_MAX) {
+ bounds = LatLngBounds::world();
+ }
+
+ auto sw = Projection::project(bounds.southwest(), z);
+ auto ne = Projection::project(bounds.northeast(), z);
+ auto se = Projection::project(bounds.southeast(), z);
+ auto nw = Projection::project(bounds.northwest(), z);
+
+ Polygon<double> p({ {sw, nw, ne, se, sw} });
+ impl = std::make_unique<TileCover::Impl>(z, p, false);
+}
+
+TileCover::TileCover(const Geometry<double>& geom, int32_t z, bool project/* = true*/)
+ : impl( std::make_unique<TileCover::Impl>(z, geom, project)) {
+}
+
+TileCover::~TileCover() {
+
+}
+
+optional<UnwrappedTileID> TileCover::next() {
+ return impl->next();
+}
+
+bool TileCover::hasNext() {
+ return impl->hasNext();
}
} // namespace util
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index b2098b59b8..c953d764d2 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -2,9 +2,11 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/style/types.hpp>
-#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
#include <vector>
+#include <memory>
namespace mbgl {
@@ -13,13 +15,31 @@ class LatLngBounds;
namespace util {
+// Helper class to stream tile-cover results per row
+class TileCover {
+public:
+ TileCover(const LatLngBounds&, int32_t z);
+ // When project == true, projects the geometry points to tile coordinates
+ TileCover(const Geometry<double>&, int32_t z, bool project = true);
+ ~TileCover();
+
+ optional<UnwrappedTileID> next();
+ bool hasNext();
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> impl;
+};
+
int32_t coveringZoomLevel(double z, style::SourceType type, uint16_t tileSize);
std::vector<UnwrappedTileID> tileCover(const TransformState&, int32_t z);
std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, int32_t z);
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>&, int32_t z);
// Compute only the count of tiles needed for tileCover
-uint64_t tileCount(const LatLngBounds&, uint8_t z, uint16_t tileSize);
+uint64_t tileCount(const LatLngBounds&, uint8_t z);
+uint64_t tileCount(const Geometry<double>&, uint8_t z);
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover_impl.cpp b/src/mbgl/util/tile_cover_impl.cpp
new file mode 100644
index 0000000000..b3fc07f7dd
--- /dev/null
+++ b/src/mbgl/util/tile_cover_impl.cpp
@@ -0,0 +1,365 @@
+#include <mbgl/util/tile_cover_impl.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+
+#include <functional>
+#include <cmath>
+#include <assert.h>
+#include <limits.h>
+#include <algorithm>
+
+namespace mbgl {
+namespace util {
+
+using PointList = std::vector<Point<double>>;
+
+struct TileSpan {
+ int32_t xmin, xmax;
+ bool winding;
+};
+
+
+// Find the first local minimum going forward in the list.
+void start_list_on_local_minimum(PointList& points) {
+ auto prev_pt = std::prev(points.end(), 2);
+ auto pt = points.begin();
+ auto next_pt = std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y <= prev_pt->y) &&
+ (pt->y < next_pt->y)) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+ //Re-close linear rings with first_pt = last_pt
+ if (points.back() == points.front()) {
+ points.pop_back();
+ }
+ std::rotate(points.begin(), pt, points.end());
+ points.push_back(*points.begin());
+}
+
+//Create a bound towards a local maximum point, starting from pt.
+Bound create_bound_towards_maximum(PointList& points, PointList::iterator& pt) {
+ if (std::distance(pt, points.end()) < 2) { return {}; }
+ if (std::distance(pt, points.end()) == 2) {
+ Bound bnd;
+ if (pt->y < std::next(pt)->y) {
+ std::copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = true;
+ }
+ else {
+ std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = false;
+ }
+ pt = points.end();
+ return bnd;
+ }
+ const auto begin = pt;
+ auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt);
+ auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y >= prev_pt->y) &&
+ (pt->y > next_pt->y )) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+
+ Bound bnd;
+ if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; };
+ bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt)));
+ std::copy(begin, next_pt, std::back_inserter(bnd.points));
+ bnd.winding = true;
+ return bnd;
+}
+
+//Create a bound towards a local minimum point, starting from pt.
+Bound create_bound_towards_minimum(PointList& points, PointList::iterator& pt) {
+ if (std::distance(pt, points.end()) < 2) { return {}; }
+ if (std::distance(pt, points.end()) == 2) {
+ Bound bnd;
+ if (pt->y < std::next(pt)->y) {
+ std::copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = true;
+ }
+ else {
+ std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = false;
+ }
+ pt = points.end();
+ return bnd;
+ }
+ auto begin = pt;
+ auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt);
+ auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y <= prev_pt->y) &&
+ (pt->y < next_pt->y)) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+
+ Bound bnd;
+ if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; };
+ bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt)));
+ //For bounds that start at a max, reverse copy so that all bounds start at a min
+ std::reverse_copy(begin, next_pt, std::back_inserter(bnd.points));
+ bnd.winding = false;
+ return bnd;
+}
+
+//Build a map of bounds and their starting Y tile coordinate.
+void build_bounds_map(PointList& points, uint32_t maxTile, BoundsMap& et, bool closed = false) {
+ if (points.size() < 2) return;
+ //While traversing closed rings, start the bounds at a local minimum
+ if (closed) {
+ start_list_on_local_minimum(points);
+ }
+
+ auto pointsIter = points.begin();
+ while (pointsIter != points.end()) {
+ Bound to_max = create_bound_towards_maximum(points, pointsIter);
+ Bound to_min = create_bound_towards_minimum(points, pointsIter);
+
+ if (to_max.points.size() > 0) {
+ // Projections may result in values beyond the bounds, clamp to max tile coordinates
+ const auto y = static_cast<uint32_t>(std::floor(clamp(to_max.points.front().y, 0.0, (double)maxTile)));
+ et[y].push_back(to_max);
+ }
+ if (to_min.points.size() > 0) {
+ const auto y = static_cast<uint32_t>(std::floor(clamp(to_min.points.front().y, 0.0, (double)maxTile)));
+ et[y].push_back(to_min);
+ }
+ }
+ assert(pointsIter == points.end());
+}
+
+void update_span(TileSpan& xp, double x) {
+ xp.xmin = std::min(xp.xmin, static_cast<int32_t>(std::floor(x)));
+ xp.xmax = std::max(xp.xmax, static_cast<int32_t>(std::ceil(x)));
+}
+
+//Build a vector of X tile-coordinates spanned by each bound.
+std::vector<TileSpan> scan_row(uint32_t y, Bounds& aet) {
+ std::vector<TileSpan> tile_range;
+ tile_range.reserve(aet.size());
+
+ for(Bound& b: aet) {
+ TileSpan xp = { INT_MAX, 0, b.winding };
+ double x;
+ const auto numEdges = b.points.size() - 1;
+ assert(numEdges >= 1);
+ while (b.currentPoint < numEdges) {
+ x = b.interpolate(y);
+ update_span(xp, x);
+
+ // If this edge ends beyond the current row, find the x-intercept where
+ // it exits the row
+ auto& p1 = b.points[b.currentPoint + 1];
+ if (p1.y > y+1) {
+ x = b.interpolate(y+1);
+ update_span(xp, x);
+ break;
+ } else if(b.currentPoint == numEdges - 1) {
+ // For last edge, consider x-intercept at the end of the edge.
+ x = p1.x;
+ update_span(xp, x);
+ }
+ b.currentPoint++;
+ }
+ tile_range.push_back(xp);
+ }
+ // Erase bounds in the active table whose current edge ends inside this row,
+ // or there are no more edges
+ auto bound = aet.begin();
+ while (bound != aet.end()) {
+ if ( bound->currentPoint == bound->points.size() - 1 &&
+ bound->points[bound->currentPoint].y <= y+1) {
+ bound = aet.erase(bound);
+ } else {
+ bound++;
+ }
+ }
+ // Sort the X-extents of each crossing bound by x_min, x_max
+ std::sort(tile_range.begin(), tile_range.end(), [] (TileSpan& a, TileSpan& b) {
+ return std::tie(a.xmin, a.xmax) < std::tie(b.xmin, b.xmax);
+ });
+
+ return tile_range;
+}
+
+struct BuildBoundsMap {
+ int32_t zoom;
+ bool project = false;
+ BuildBoundsMap(int32_t z, bool p): zoom(z), project(p) {}
+
+ void buildTable(const std::vector<Point<double>>& points, BoundsMap& et, bool closed = false) const {
+ PointList projectedPoints;
+ if (project) {
+ projectedPoints.reserve(points.size());
+ for(const auto&p : points) {
+ projectedPoints.push_back(
+ Projection::project(LatLng{ p.y, p.x }, zoom));
+ }
+ } else {
+ projectedPoints.insert(projectedPoints.end(), points.begin(), points.end());
+ }
+ build_bounds_map(projectedPoints, 1 << zoom, et, closed);
+ }
+
+ void buildPolygonTable(const Polygon<double>& polygon, BoundsMap& et) const {
+ for(const auto&ring : polygon) {
+ buildTable(ring, et, true);
+ }
+ }
+ BoundsMap operator()(const Point<double>&p) const {
+ Bound bnd;
+ auto point = p;
+ if(project) {
+ point = Projection::project(LatLng{p.y, p.x}, zoom);
+ }
+ bnd.points.insert(bnd.points.end(), 2, point);
+ bnd.winding = false;
+ BoundsMap et;
+ const auto y = static_cast<uint32_t>(std::floor(clamp(point.y, 0.0, (double)(1 << zoom))));
+ et[y].push_back(bnd);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiPoint<double>& points) const {
+ BoundsMap et;
+ for (const Point<double>& p: points) {
+ Bound bnd;
+ auto point = p;
+ if(project) {
+ point = Projection::project(LatLng{p.y, p.x}, zoom);
+ }
+ bnd.points.insert(bnd.points.end(), 2, point);
+ bnd.winding = false;
+ const auto y = static_cast<uint32_t>(std::floor(clamp(point.y, 0.0, (double)(1 << zoom))));
+ et[y].push_back(bnd);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const LineString<double>& lines) const {
+ BoundsMap et;
+ buildTable(lines, et);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiLineString<double>& lines) const {
+ BoundsMap et;
+ for(const auto&line : lines) {
+ buildTable(line, et);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const Polygon<double>& polygon) const {
+ BoundsMap et;
+ buildPolygonTable(polygon, et);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiPolygon<double>& polygons) const {
+ BoundsMap et;
+ for(const auto& polygon: polygons) {
+ buildPolygonTable(polygon, et);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const mapbox::geometry::geometry_collection<double>&) const {
+ return {};
+ }
+};
+
+TileCover::Impl::Impl(int32_t z, const Geometry<double>& geom, bool project)
+ : zoom(z) {
+ ToFeatureType toFeatureType;
+ isClosed = apply_visitor(toFeatureType, geom) == FeatureType::Polygon;
+
+ BuildBoundsMap toBoundsMap(z, project);
+ boundsMap = apply_visitor(toBoundsMap, geom);
+ if (boundsMap.size() == 0) return;
+
+ //Iniitalize the active edge table, and current row span
+ currentBounds = boundsMap.begin();
+ tileY = 0;
+ nextRow();
+ if (tileXSpans.empty()) return;
+ tileX = tileXSpans.front().first;
+}
+
+void TileCover::Impl::nextRow() {
+ // Update AET for next row
+ if (currentBounds != boundsMap.end()) {
+ if (activeBounds.size() == 0 && currentBounds->first > tileY) {
+ //For multi-geoms: use the next row with an edge table starting point
+ tileY = currentBounds->first;
+ }
+ if (tileY == currentBounds->first) {
+
+ std::move(currentBounds->second.begin(), currentBounds->second.end(), std::back_inserter(activeBounds));
+ currentBounds++;
+ }
+ }
+ //Scan aet and update currenRange with x_min, x_max pairs
+ auto xps = util::scan_row(tileY, activeBounds);
+ if (xps.size() == 0) {
+ return;
+ }
+
+ auto x_min = xps[0].xmin;
+ auto x_max = xps[0].xmax;
+ int32_t nzRule = xps[0].winding ? 1 : -1;
+ for (size_t i = 1; i < xps.size(); i++) {
+ auto xp = xps[i];
+ if (!(isClosed && nzRule != 0)) {
+ if (xp.xmin > x_max && xp.xmax >= x_max) {
+ tileXSpans.emplace(x_min, x_max);
+ x_min = xp.xmin;
+ }
+ }
+ nzRule += xp.winding ? 1 : -1;
+ x_max = std::max(x_min, xp.xmax);
+ }
+ tileXSpans.emplace(x_min, x_max);
+}
+
+bool TileCover::Impl::hasNext() const {
+ return (!tileXSpans.empty() && tileX < tileXSpans.front().second && tileY < (1u << zoom));
+}
+
+optional<UnwrappedTileID> TileCover::Impl::next() {
+ if (!hasNext()) return {};
+
+ const auto x = tileX;
+ const auto y = tileY;
+ tileX++;
+ if (tileX >= tileXSpans.front().second) {
+ tileXSpans.pop();
+ if(tileXSpans.empty()) {
+ tileY++;
+ nextRow();
+ }
+ if (!tileXSpans.empty()) {
+ tileX = tileXSpans.front().first;
+ }
+ }
+ return UnwrappedTileID(zoom, x, y);
+}
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover_impl.hpp b/src/mbgl/util/tile_cover_impl.hpp
new file mode 100644
index 0000000000..7c16718984
--- /dev/null
+++ b/src/mbgl/util/tile_cover_impl.hpp
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <vector>
+#include <map>
+#include <queue>
+
+namespace mbgl {
+
+class TransformState;
+class LatLngBounds;
+
+namespace util {
+
+struct Bound;
+
+using Bounds = std::vector<Bound>;
+using BoundsMap = std::map<uint32_t, Bounds>;
+
+// A chain of points from a local minimum to a local maximum. `winding` indicates
+// the direction of the original geometry.
+struct Bound {
+ std::vector<Point<double>> points;
+ size_t currentPoint = 0;
+ bool winding = false;
+
+ Bound() = default;
+ Bound(const Bound& rhs) {
+ points = rhs.points;
+ currentPoint = rhs.currentPoint;
+ winding = rhs.winding;
+ }
+ Bound& operator=(Bound&& rhs) {
+ points = std::move(rhs.points);
+ currentPoint = rhs.currentPoint;
+ winding = rhs.winding;
+ return *this;
+ }
+
+ // Compute the interpolated x coordinate at y for the current edge
+ double interpolate(uint32_t y) {
+ const auto& p0 = points[currentPoint];
+ const auto& p1 = points[currentPoint + 1];
+
+ const auto dx = p1.x - p0.x;
+ const auto dy = p1.y - p0.y;
+ auto x = p0.x;
+ if (dx == 0) {
+ return x;
+ } else if (dy == 0){
+ return y <= p0.y ? p0.x : p1.x;
+ }
+ if (y < p0.y) return x;
+ if (y > p1.y) return p1.x;
+ x = (dx / dy) * (y - p0.y) + p0.x;
+ return x;
+ }
+};
+
+class TileCover::Impl {
+public:
+ Impl(int32_t z, const Geometry<double>& geom, bool project = true);
+ ~Impl() = default;
+
+ optional<UnwrappedTileID> next();
+ bool hasNext() const;
+
+private:
+ using TileSpans = std::queue<std::pair<int32_t, int32_t>>;
+
+ void nextRow();
+
+ const int32_t zoom;
+ bool isClosed;
+
+ BoundsMap boundsMap;
+ BoundsMap::iterator currentBounds;
+ // List of bounds that begin at or before `tileY`
+ Bounds activeBounds;
+
+ TileSpans tileXSpans;
+ uint32_t tileY;
+ int32_t tileX;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/tiny_sdf.cpp b/src/mbgl/util/tiny_sdf.cpp
index 60839357d5..6edcd83bc2 100644
--- a/src/mbgl/util/tiny_sdf.cpp
+++ b/src/mbgl/util/tiny_sdf.cpp
@@ -95,7 +95,7 @@ AlphaImage transformRasterToSDF(const AlphaImage& rasterInput, double radius, do
for (uint32_t i = 0; i < size; i++) {
double distance = gridOuter[i] - gridInner[i];
- sdf.data[i] = std::max(0l, std::min(255l, std::lround(255.0 - 255.0 * (distance / radius + cutoff))));
+ sdf.data[i] = std::max(0l, std::min(255l, ::lround(255.0 - 255.0 * (distance / radius + cutoff))));
}
return sdf;
diff --git a/src/mbgl/util/token.hpp b/src/mbgl/util/token.hpp
index 149661e47e..dea12f9412 100644
--- a/src/mbgl/util/token.hpp
+++ b/src/mbgl/util/token.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <mbgl/util/optional.hpp>
+
#include <map>
#include <string>
#include <algorithm>
@@ -25,7 +27,14 @@ std::string replaceTokens(const std::string &source, const Lookup &lookup) {
if (pos != end) {
for (brace++; brace != end && tokenReservedChars.find(*brace) == std::string::npos; brace++);
if (brace != end && *brace == '}') {
- result.append(lookup({ pos + 1, brace }));
+ std::string key { pos + 1, brace };
+ if (optional<std::string> replacement = lookup(key)) {
+ result.append(*replacement);
+ } else {
+ result.append("{");
+ result.append(key);
+ result.append("}");
+ }
pos = brace + 1;
} else {
result.append(pos, brace);
diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp
index 1f6dab9639..a4263502ef 100644
--- a/src/mbgl/util/url.cpp
+++ b/src/mbgl/util/url.cpp
@@ -130,7 +130,7 @@ Path::Path(const std::string& str, const size_t pos, const size_t count)
}
std::string transformURL(const std::string& tpl, const std::string& str, const URL& url) {
- auto result = util::replaceTokens(tpl, [&](const std::string& token) -> std::string {
+ auto result = util::replaceTokens(tpl, [&](const std::string& token) -> optional<std::string> {
if (token == "path") {
return str.substr(url.path.first, url.path.second);
} else if (token == "domain") {
@@ -146,8 +146,9 @@ std::string transformURL(const std::string& tpl, const std::string& str, const U
} else if (token == "extension") {
const Path path(str, url.path.first, url.path.second);
return str.substr(path.extension.first, path.extension.second);
+ } else {
+ return {};
}
- return "";
});
// Append the query string if it exists.
diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp
index 6cb148a349..a94cf122bf 100644
--- a/test/api/custom_layer.test.cpp
+++ b/test/api/custom_layer.test.cpp
@@ -48,7 +48,7 @@ public:
MBGL_CHECK_ERROR(glCompileShader(fragmentShader));
MBGL_CHECK_ERROR(glAttachShader(program, fragmentShader));
MBGL_CHECK_ERROR(glLinkProgram(program));
- a_pos = glGetAttribLocation(program, "a_pos");
+ a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
GLfloat triangle[] = { 0, 0.5, 0.5, -0.5, -0.5, -0.5 };
MBGL_CHECK_ERROR(glGenBuffers(1, &buffer));
diff --git a/test/fixtures/offline_database/satellite_test.db b/test/fixtures/offline_database/satellite_test.db
new file mode 100644
index 0000000000..95dd8617ff
--- /dev/null
+++ b/test/fixtures/offline_database/satellite_test.db
Binary files differ
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index 8393fd130d..9b28b2e01a 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -110,10 +110,11 @@ TEST(Buckets, SymbolBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
std::vector<SymbolInstance> symbolInstances;
gl::Context context;
- SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(symbolInstances) };
+ SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances) };
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
diff --git a/test/src/mbgl/test/util.cpp b/test/src/mbgl/test/util.cpp
index 028a0a9d51..30eea19bdf 100644
--- a/test/src/mbgl/test/util.cpp
+++ b/test/src/mbgl/test/util.cpp
@@ -11,10 +11,6 @@
#include <unistd.h>
-#ifndef NODE_EXECUTABLE
-#define NODE_EXECUTABLE node
-#endif
-
#define xstr(s) str(s)
#define str(s) #s
@@ -54,8 +50,6 @@ Server::Server(const char* script) {
const char* executable = xstr(NODE_EXECUTABLE);
- fprintf(stderr, "executable: %s\n", executable);
-
// Launch the actual server process.
int ret = execl(executable, executable, script, nullptr);
diff --git a/test/src/mbgl/test/util.hpp b/test/src/mbgl/test/util.hpp
index 7a8d78897e..9f56841dcc 100644
--- a/test/src/mbgl/test/util.hpp
+++ b/test/src/mbgl/test/util.hpp
@@ -5,20 +5,24 @@
#endif
#if ANDROID
-#define TEST_READ_ONLY 0
-#define TEST_HAS_SERVER 0
+ #define TEST_READ_ONLY 0
+ #undef TEST_HAS_SERVER
+ #define TEST_HAS_SERVER 0
#elif TARGET_OS_IOS
-#define TEST_READ_ONLY 1
-#define TEST_HAS_SERVER 0
+ #define TEST_READ_ONLY 1
+ #undef TEST_HAS_SERVER
+ #define TEST_HAS_SERVER 0
#else
-#define TEST_READ_ONLY 0
-#define TEST_HAS_SERVER 1
+ #define TEST_READ_ONLY 0
+ #ifndef TEST_HAS_SERVER
+ #define TEST_HAS_SERVER 1
+ #endif
#endif
#if TARGET_OS_SIMULATOR
-#define TEST_IS_SIMULATOR 1
+ #define TEST_IS_SIMULATOR 1
#else
-#define TEST_IS_SIMULATOR 0
+ #define TEST_IS_SIMULATOR 0
#endif
#if !TEST_IS_SIMULATOR && !CI_BUILD
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index 94daf59c02..656231eebe 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -38,6 +38,10 @@ void writeFile(const char* name, const std::string& data) {
mbgl::util::write_file(name, data);
}
+void copyFile(const char* orig, const char* dest) {
+ mbgl::util::write_file(dest, mbgl::util::read_file(orig));
+}
+
} // namespace
TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) {
@@ -62,7 +66,7 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(SchemaVersion)) {
std::string path("test/fixtures/offline_database/offline.db");
{
- mapbox::sqlite::Database db(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
db.exec("PRAGMA user_version = 1");
}
@@ -143,6 +147,36 @@ TEST(OfflineDatabase, PutResource) {
EXPECT_EQ("second", *updateGetResult->data);
}
+TEST(OfflineDatabase, TEST_REQUIRES_WRITE(GetResourceFromOfflineRegion)) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/offline_database");
+ deleteFile("test/fixtures/offline_database/satellite.db");
+ copyFile("test/fixtures/offline_database/satellite_test.db", "test/fixtures/offline_database/satellite.db");
+
+ OfflineDatabase db("test/fixtures/offline_database/satellite.db", mapbox::sqlite::ReadOnly);
+
+ Resource resource = Resource::style("mapbox://styles/mapbox/satellite-v9");
+ ASSERT_TRUE(db.get(resource));
+}
+
+TEST(OfflineDatabase, PutAndGetResource) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Response response1;
+ response1.data = std::make_shared<std::string>("foobar");
+
+ Resource resource = Resource::style("mapbox://example.com/style");
+
+ db.put(resource, response1);
+
+ auto response2 = db.get(resource);
+
+ ASSERT_EQ(*response1.data, *(*response2).data);
+}
+
TEST(OfflineDatabase, PutTile) {
using namespace mbgl;
@@ -565,40 +599,45 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) {
}
static int databasePageCount(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma page_count");
- stmt.run();
- return stmt.get<int>(0);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly);
+ mapbox::sqlite::Statement stmt{ db, "pragma page_count" };
+ mapbox::sqlite::Query query{ stmt };
+ query.run();
+ return query.get<int>(0);
}
static int databaseUserVersion(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma user_version");
- stmt.run();
- return stmt.get<int>(0);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly);
+ mapbox::sqlite::Statement stmt{ db, "pragma user_version" };
+ mapbox::sqlite::Query query{ stmt };
+ query.run();
+ return query.get<int>(0);
}
static std::string databaseJournalMode(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma journal_mode");
- stmt.run();
- return stmt.get<std::string>(0);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly);
+ mapbox::sqlite::Statement stmt{ db, "pragma journal_mode" };
+ mapbox::sqlite::Query query{ stmt };
+ query.run();
+ return query.get<std::string>(0);
}
static int databaseSyncMode(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma synchronous");
- stmt.run();
- return stmt.get<int>(0);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly);
+ mapbox::sqlite::Statement stmt{ db, "pragma synchronous" };
+ mapbox::sqlite::Query query{ stmt };
+ query.run();
+ return query.get<int>(0);
}
static std::vector<std::string> databaseTableColumns(const std::string& path, const std::string& name) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly);
const auto sql = std::string("pragma table_info(") + name + ")";
- mapbox::sqlite::Statement stmt = db.prepare(sql.c_str());
+ mapbox::sqlite::Statement stmt{ db, sql.c_str() };
+ mapbox::sqlite::Query query{ stmt };
std::vector<std::string> columns;
- while (stmt.run()) {
- columns.push_back(stmt.get<std::string>(1));
+ while (query.run()) {
+ columns.push_back(query.get<std::string>(1));
}
return columns;
}
diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp
index 36715a2fd0..553736a0b1 100644
--- a/test/storage/sqlite.test.cpp
+++ b/test/storage/sqlite.test.cpp
@@ -6,33 +6,32 @@
TEST(SQLite, Statement) {
using namespace mbgl;
- mapbox::sqlite::Database db(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
db.exec("CREATE TABLE test (id INTEGER);");
- mapbox::sqlite::Statement stmt1 = db.prepare("INSERT INTO test (id) VALUES (?1);");
- ASSERT_EQ(stmt1.lastInsertRowId(), 0);
- ASSERT_EQ(stmt1.changes(), 0u);
- stmt1.bind(1, 10);
- stmt1.run();
- ASSERT_EQ(stmt1.lastInsertRowId(), 1);
- ASSERT_EQ(stmt1.changes(), 1u);
+ mapbox::sqlite::Statement stmt1{ db, "INSERT INTO test (id) VALUES (?1);" };
+ mapbox::sqlite::Query query1{ stmt1 };
+ ASSERT_EQ(query1.lastInsertRowId(), 0);
+ ASSERT_EQ(query1.changes(), 0u);
+ query1.bind(1, 10);
+ query1.run();
+ ASSERT_EQ(query1.lastInsertRowId(), 1);
+ ASSERT_EQ(query1.changes(), 1u);
- mapbox::sqlite::Statement stmt2 = db.prepare("INSERT INTO test (id) VALUES (?1);");
- ASSERT_EQ(stmt2.lastInsertRowId(), 0);
- ASSERT_EQ(stmt2.changes(), 0u);
- stmt2.bind(1, 20);
- stmt2.run();
- ASSERT_EQ(stmt2.lastInsertRowId(), 2);
- ASSERT_EQ(stmt2.changes(), 1u);
+ mapbox::sqlite::Statement stmt2{ db, "INSERT INTO test (id) VALUES (?1);" };
+ mapbox::sqlite::Query query2{ stmt2 };
+ ASSERT_EQ(query2.lastInsertRowId(), 0);
+ ASSERT_EQ(query2.changes(), 0u);
+ query2.bind(1, 20);
+ query2.run();
+ ASSERT_EQ(query2.lastInsertRowId(), 2);
+ ASSERT_EQ(query2.changes(), 1u);
}
-TEST(SQLite, TEST_REQUIRES_WRITE(CantOpenException)) {
- try {
- // Should throw a CANTOPEN when the database doesn't exist,
- // make sure all the backends behave the same way.
- mapbox::sqlite::Database("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly);
- FAIL();
- } catch (mapbox::sqlite::Exception& ex) {
- ASSERT_EQ(ex.code, mapbox::sqlite::Exception::Code::CANTOPEN);
- }
+TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) {
+ // Should return a CANTOPEN exception when the database doesn't exist,
+ // make sure all the backends behave the same way.
+ auto result = mapbox::sqlite::Database::tryOpen("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly);
+ ASSERT_TRUE(result.is<mapbox::sqlite::Exception>());
+ ASSERT_EQ(result.get<mapbox::sqlite::Exception>().code, mapbox::sqlite::ResultCode::CantOpen);
}
diff --git a/test/style/conversion/tileset.test.cpp b/test/style/conversion/tileset.test.cpp
index f10aa0e318..f405fb1361 100644
--- a/test/style/conversion/tileset.test.cpp
+++ b/test/style/conversion/tileset.test.cpp
@@ -66,7 +66,7 @@ TEST(Tileset, BoundsAreClamped) {
Error error;
mbgl::optional<Tileset> converted = convertJSON<Tileset>(R"JSON({
"tiles": ["http://mytiles"],
- "bounds": [-181.0000005,-90,180.00000000000006,90]
+ "bounds": [-181.0000005,-90.000000006,180.00000000000006,91]
})JSON", error);
EXPECT_TRUE((bool) converted);
EXPECT_EQ(converted->bounds, LatLngBounds::hull({90, -180}, {-90, 180}));
diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp
index fe5c261be1..709624a50f 100644
--- a/test/style/expression/expression.test.cpp
+++ b/test/style/expression/expression.test.cpp
@@ -24,11 +24,15 @@ TEST(Expression, IsExpression) {
spec["expression_name"].IsObject() &&
spec["expression_name"].HasMember("values") &&
spec["expression_name"]["values"].IsObject());
-
+
const auto& allExpressions = spec["expression_name"]["values"];
-
+
for(auto& entry : allExpressions.GetObject()) {
const std::string name { entry.name.GetString(), entry.name.GetStringLength() };
+ if (name == "collator" || name == "line-progress" || name == "resolved-locale" || name == "feature-state") {
+ // Not yet implemented
+ continue;
+ }
JSDocument document;
document.Parse<0>(R"([")" + name + R"("])");
diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp
index 794c2b59a1..5d255a6105 100644
--- a/test/text/cross_tile_symbol_index.test.cpp
+++ b/test/text/cross_tile_symbol_index.test.cpp
@@ -25,12 +25,13 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit"));
mainInstances.push_back(makeSymbolInstance(2000, 2000, u"Toronto"));
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(mainID, mainBucket, maxCrossTileID);
@@ -45,7 +46,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
childInstances.push_back(makeSymbolInstance(2000, 2000, u"Windsor"));
childInstances.push_back(makeSymbolInstance(3000, 3000, u"Toronto"));
childInstances.push_back(makeSymbolInstance(4001, 4001, u"Toronto"));
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(childID, childBucket, maxCrossTileID);
@@ -61,7 +62,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
OverscaledTileID parentID(5, 0, 5, 4, 4);
std::vector<SymbolInstance> parentInstances;
parentInstances.push_back(makeSymbolInstance(500, 500, u"Detroit"));
- SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(parentInstances) };
+ SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances) };
parentBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(parentID, parentBucket, maxCrossTileID);
@@ -77,7 +78,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
std::vector<SymbolInstance> grandchildInstances;
grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Detroit"));
grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Windsor"));
- SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(grandchildInstances) };
+ SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances) };
grandchildBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(grandchildID, grandchildBucket, maxCrossTileID);
@@ -98,17 +99,18 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit"));
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
OverscaledTileID childID(7, 0, 7, 16, 16);
std::vector<SymbolInstance> childInstances;
childInstances.push_back(makeSymbolInstance(2000, 2000, u"Detroit"));
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns a new id
@@ -137,12 +139,13 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
OverscaledTileID childID(7, 0, 7, 16, 16);
@@ -150,7 +153,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // A'
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // B'
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // C'
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
@@ -174,19 +177,20 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID tileID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> firstInstances;
firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A
firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B
- SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(firstInstances) };
+ SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances) };
firstBucket.bucketInstanceId = ++maxBucketInstanceId;
std::vector<SymbolInstance> secondInstances;
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A'
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B'
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // C'
- SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(secondInstances) };
+ SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances) };
secondBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp
index 933c18b5ea..7defa761af 100644
--- a/test/util/tile_cover.test.cpp
+++ b/test/util/tile_cover.test.cpp
@@ -2,6 +2,8 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/map/transform.hpp>
+#include <algorithm>
+
#include <gtest/gtest.h>
using namespace mbgl;
@@ -22,8 +24,8 @@ TEST(TileCover, Antarctic) {
TEST(TileCover, WorldZ0) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 0, 0, 0 },
- }),
+ { 0, 0, 0 },
+ }),
util::tileCover(LatLngBounds::world(), 0));
}
@@ -37,15 +39,15 @@ TEST(TileCover, Pitch) {
transform.setPitch(40.0 * M_PI / 180.0);
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 }
- }),
+ { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 }
+ }),
util::tileCover(transform.getState(), 2));
}
TEST(TileCover, WorldZ1) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
- }),
+ { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
+ }),
util::tileCover(LatLngBounds::world(), 1));
}
@@ -59,21 +61,44 @@ TEST(TileCover, SingletonZ1) {
util::tileCover(LatLngBounds::singleton({ 0, 0 }), 1));
}
+TEST(TileCoverStream, Arctic) {
+ auto bounds = LatLngBounds::hull({ 84, -180 }, { 70, 180 });
+ auto zoom = 3;
+ util::TileCover tc(bounds, zoom);
+ auto results = util::tileCover(bounds, zoom);
+ std::vector<UnwrappedTileID> t;
+ while(tc.hasNext()) {
+ t.push_back(*tc.next());
+ };
+ EXPECT_EQ(t.size(), results.size());
+}
+
+TEST(TileCoverStream, WorldZ1) {
+ auto zoom = 1;
+ util::TileCover tc(LatLngBounds::world(), zoom);
+ std::vector<UnwrappedTileID> t;
+ while(tc.hasNext()) {
+ t.push_back(*tc.next());
+ };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 1, 0, 0 }, { 1, 1, 0 }, { 1, 0, 1 }, { 1, 1, 1 },
+ }), t);
+}
+
static const LatLngBounds sanFrancisco =
LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
TEST(TileCover, SanFranciscoZ0) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 0, 0, 0 },
- }),
+ { 0, 0, 0 },
+ }),
util::tileCover(sanFrancisco, 0));
}
TEST(TileCover, SanFranciscoZ10) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 },
-
- }),
+ { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 },
+ }),
util::tileCover(sanFrancisco, 10));
}
@@ -85,11 +110,192 @@ TEST(TileCover, SanFranciscoZ0Wrapped) {
util::tileCover(sanFranciscoWrapped, 0));
}
+TEST(TileCover, GeomPoint) {
+ auto point = Point<double>{ -122.5744, 37.6609 };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ {2 ,0 ,1 } }),
+ util::tileCover(point, 2));
+}
+
+TEST(TileCover, GeomMultiPoint) {
+ auto points = MultiPoint<double>{ { -122.5, 37.76 }, { -122.4, 37.76} };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ {20, 167480, 405351}, {20, 167772, 405351} }),
+ util::tileCover(points, 20));
+}
+
+TEST(TileCover, GeomLineZ10) {
+ auto lineCover = util::tileCover(LineString<double>{
+ {-121.49368286132812,38.57903714667459},
+ {-122.4422836303711,37.773157169570695}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 10, 166, 392}, {10, 165, 393}, {10, 166, 393},
+ {10, 164, 394}, {10, 165, 394}, {10,163,395}, {10, 164, 395}
+ }),lineCover);
+
+}
+
+TEST(TileCover, WrappedGeomLineZ10) {
+ auto lineCover = util::tileCover(LineString<double>{
+ {-179.93342914581299,38.892101707724315},
+ {-180.02394485473633,38.89203490311832}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, -1, 391 }, { 10, 0, 391 } }),
+ lineCover);
+
+ lineCover = util::tileCover(LineString<double>{
+ {179.93342914581299,38.892101707724315},
+ {180.02394485473633,38.89203490311832}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, 1023, 391 }, { 10, 1024, 391 } }),
+ lineCover);
+}
+
+TEST(TileCover, GeomMultiLineString) {
+ auto geom = MultiLineString<double>{
+ { { -122.5, 37.76 }, { -122.4, 37.76} },
+ { { -122.5, 37.72 }, { -122.4, 37.72} } };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ {14, 2616, 6333}, {14, 2617, 6333}, {14, 2618, 6333},
+ {14, 2619, 6333}, {14, 2620, 6333}, {14, 2621, 6333},
+ {14, 2616, 6335}, {14, 2617, 6335}, {14, 2618, 6335},
+ {14, 2619, 6335}, {14, 2620, 6335}, {14, 2621, 6335}}),
+ util::tileCover(geom, 14));
+}
+
+TEST(TileCover, GeomPolygon) {
+ auto polygon = Polygon<double>{
+ {
+ {5.09765625,53.067626642387374},
+ {2.373046875,43.389081939117496},
+ {-4.74609375,48.45835188280866},
+ {-1.494140625,37.09023980307208},
+ {22.587890625,36.24427318493909},
+ {31.640625,46.13417004624326},
+ {17.841796875,54.7246201949245},
+ {5.09765625,53.067626642387374},
+ },{
+ {19.6875,49.66762782262194},
+ {22.8515625,43.51668853502906},
+ {13.623046875,45.089035564831036},
+ {16.34765625,39.095962936305476},
+ {5.185546875,41.244772343082076},
+ {8.701171874999998,50.233151832472245},
+ {19.6875,49.66762782262194}
+ }
+ };
+
+ auto results = util::tileCover(polygon, 8);
+
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 134, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end());
+ // Should have a hole
+ EXPECT_EQ(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end());
+}
+
+TEST(TileCover, GeomMultiPolygon) {
+ auto multiPolygon = MultiPolygon<double>{
+ {{
+ {5.09765625,53.067626642387374},
+ {2.373046875,43.389081939117496},
+ {-4.74609375,48.45835188280866},
+ {-1.494140625,37.09023980307208},
+ {22.587890625,36.24427318493909},
+ {31.640625,46.13417004624326},
+ {17.841796875,54.7246201949245},
+ {5.09765625,53.067626642387374},
+ }},{{
+ {59.150390625,45.460130637921004},
+ {65.126953125,41.11246878918088},
+ {69.169921875,47.45780853075031},
+ {63.896484375,50.064191736659104},
+ {59.150390625,45.460130637921004}
+ }}
+ };
+ auto results = util::tileCover(multiPolygon, 8);
+
+ EXPECT_EQ(424u, results.size());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 174, 94}), results.end());
+}
+
+TEST(TileCover, GeomSanFranciscoPoly) {
+ auto sanFranciscoGeom = Polygon<double>{
+ {
+ {-122.5143814086914,37.779127216982424},
+ {-122.50811576843262,37.72721239056709},
+ {-122.50313758850099,37.70820178063929},
+ {-122.3938751220703,37.707454835665274},
+ {-122.37567901611328,37.70663997801684},
+ {-122.36297607421874,37.71343018466285},
+ {-122.354736328125,37.727280276860036},
+ {-122.36469268798828,37.73868429065797},
+ {-122.38014221191408,37.75442980295571},
+ {-122.38391876220702,37.78753873820529},
+ {-122.35919952392578,37.8065289741725},
+ {-122.35679626464844,37.820632846207864},
+ {-122.3712158203125,37.835276322922695},
+ {-122.3818588256836,37.82958198283902},
+ {-122.37190246582031,37.80788523279169},
+ {-122.38735198974608,37.791337175930686},
+ {-122.40966796874999,37.812767557570204},
+ {-122.46425628662108,37.807071480609274},
+ {-122.46803283691405,37.810326435534755},
+ {-122.47901916503906,37.81168262440736},
+ {-122.48966217041016,37.78916666399649},
+ {-122.50579833984375,37.78781006166096},
+ {-122.5143814086914,37.779127216982424}
+ }
+ };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 12, 654, 1582 }, { 12, 655, 1582 },
+ { 12, 654, 1583 }, { 12, 655, 1583 },
+ { 12, 654, 1584 }, { 12, 655, 1584 }
+ }), util::tileCover(sanFranciscoGeom, 12));
+}
+
+TEST(TileCover, GeomInvalid) {
+ auto point = Point<double>{ -122.5744, 97.6609 };
+ EXPECT_THROW(util::tileCover(point, 2), std::domain_error);
+
+ auto badPoly = Polygon<double> { { {1.0, 35.0} } };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ }), util::tileCover(badPoly, 16));
+
+ //Should handle open polygons.
+ badPoly = Polygon<double> { { {1.0, 34.2}, {1.0, 34.4}, {0.5, 34.3} } };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 10, 513, 407 }, { 10, 514, 407},
+ { 10, 513, 408 }, { 10, 514, 408}
+ }), util::tileCover(badPoly, 10));
+}
+
+
+TEST(TileCount, World) {
+ EXPECT_EQ(1u, util::tileCount(LatLngBounds::world(), 0));
+ EXPECT_EQ(4u, util::tileCount(LatLngBounds::world(), 1));
+}
+
TEST(TileCount, SanFranciscoZ10) {
- EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10, util::tileSize));
+ EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10));
+}
+
+TEST(TileCount, SanFranciscoWrappedZ10) {
+ EXPECT_EQ(4u, util::tileCount(sanFranciscoWrapped, 10));
}
TEST(TileCount, SanFranciscoZ22) {
- EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22, util::tileSize));
+ EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22));
}
+TEST(TileCount, BoundsCrossingAntimeridian) {
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+
+ EXPECT_EQ(1u, util::tileCount(crossingBounds, 0));
+ EXPECT_EQ(4u, util::tileCount(crossingBounds, 3));
+ EXPECT_EQ(8u, util::tileCount(crossingBounds, 4));
+}
diff --git a/test/util/tile_range.test.cpp b/test/util/tile_range.test.cpp
index c4c37c74d7..83ac5096a5 100644
--- a/test/util/tile_range.test.cpp
+++ b/test/util/tile_range.test.cpp
@@ -52,14 +52,14 @@ TEST(TileRange, ContainsWrappedBounds) {
TEST(TileRange, ContainsBoundsCrossingAntimeridian) {
{
- auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
- auto range = util::TileRange::fromLatLngBounds(cossingBounds, 1);
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+ auto range = util::TileRange::fromLatLngBounds(crossingBounds, 1);
EXPECT_TRUE(range.contains(CanonicalTileID(1, 1, 1)));
EXPECT_TRUE(range.contains(CanonicalTileID(1, 0, 0)));
}
{
- auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
- auto range = util::TileRange::fromLatLngBounds(cossingBounds, 6);
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+ auto range = util::TileRange::fromLatLngBounds(crossingBounds, 6);
EXPECT_FALSE(range.contains(CanonicalTileID(6, 55, 34)));
EXPECT_FALSE(range.contains(CanonicalTileID(6, 5, 28)));
EXPECT_TRUE(range.contains(CanonicalTileID(6, 63, 28)));
diff --git a/test/util/token.test.cpp b/test/util/token.test.cpp
index a2885dc8dd..d0cf1e31cf 100644
--- a/test/util/token.test.cpp
+++ b/test/util/token.test.cpp
@@ -47,4 +47,7 @@ TEST(Token, replaceTokens) {
if (token == "HØYDE") return "150";
return "";
}));
+ EXPECT_EQ("{unknown}", mbgl::util::replaceTokens("{unknown}", [](const std::string&) -> optional<std::string> {
+ return {};
+ }));
}