summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Crocker <jesse@gaiagps.com>2017-03-01 11:15:11 -0700
committerJesse Crocker <jesse@gaiagps.com>2017-03-01 11:15:11 -0700
commit9e8dc9a9e3e86adb9987ae69766cc42c7d9efece (patch)
treef5f0abd4d342c89ad0405d01969f9d6caecc1c90
parent16fb0672e64a72b7400c321d55858b73cd5d8c3f (diff)
parentf28d75dccd9bf4a7615df87faccc5cf5eff8df89 (diff)
downloadqtlocation-mapboxgl-9e8dc9a9e3e86adb9987ae69766cc42c7d9efece.tar.gz
Merge remote-tracking branch 'origin/master' into feature/custom-vector-source
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules7
m---------.mason0
-rw-r--r--.travis.yml51
-rw-r--r--.tx/config25
-rw-r--r--CMakeLists.txt34
-rw-r--r--Makefile169
-rw-r--r--benchmark/api/query.benchmark.cpp2
-rw-r--r--cmake/NodeJS.cmake600
-rw-r--r--cmake/core-files.cmake60
-rw-r--r--cmake/core.cmake22
-rw-r--r--cmake/glfw.cmake7
-rw-r--r--cmake/mason.cmake212
-rw-r--r--cmake/mbgl.cmake29
-rw-r--r--cmake/node.cmake10
-rw-r--r--cmake/shaders.cmake32
-rw-r--r--cmake/test-files.cmake12
-rw-r--r--cmake/test.cmake1
-rw-r--r--common/ca-bundle.crt2017
-rw-r--r--include/mbgl/annotation/annotation.hpp11
-rw-r--r--include/mbgl/gl/gl.hpp2
-rw-r--r--include/mbgl/map/backend.hpp17
-rw-r--r--include/mbgl/map/backend_scope.hpp18
-rw-r--r--include/mbgl/map/map.hpp38
-rw-r--r--include/mbgl/storage/default_file_source.hpp25
-rw-r--r--include/mbgl/storage/online_file_source.hpp6
-rw-r--r--include/mbgl/storage/response.hpp4
-rw-r--r--include/mbgl/style/conversion/data_driven_property_value.hpp46
-rw-r--r--include/mbgl/style/conversion/filter.hpp144
-rw-r--r--include/mbgl/style/conversion/function.hpp380
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp58
-rw-r--r--include/mbgl/style/conversion/make_property_setters.hpp.ejs1
-rw-r--r--include/mbgl/style/conversion/property_setter.hpp26
-rw-r--r--include/mbgl/style/conversion/property_value.hpp2
-rw-r--r--include/mbgl/style/conversion/transition_options.hpp45
-rw-r--r--include/mbgl/style/data_driven_property_value.hpp56
-rw-r--r--include/mbgl/style/filter.hpp101
-rw-r--r--include/mbgl/style/filter_evaluator.hpp92
-rw-r--r--include/mbgl/style/function.hpp40
-rw-r--r--include/mbgl/style/function/camera_function.hpp41
-rw-r--r--include/mbgl/style/function/categorical_stops.hpp40
-rw-r--r--include/mbgl/style/function/composite_categorical_stops.hpp30
-rw-r--r--include/mbgl/style/function/composite_exponential_stops.hpp35
-rw-r--r--include/mbgl/style/function/composite_function.hpp116
-rw-r--r--include/mbgl/style/function/composite_interval_stops.hpp32
-rw-r--r--include/mbgl/style/function/exponential_stops.hpp54
-rw-r--r--include/mbgl/style/function/identity_stops.hpp20
-rw-r--r--include/mbgl/style/function/interval_stops.hpp49
-rw-r--r--include/mbgl/style/function/source_function.hpp59
-rw-r--r--include/mbgl/style/layers/background_layer.hpp6
-rw-r--r--include/mbgl/style/layers/circle_layer.hpp61
-rw-r--r--include/mbgl/style/layers/fill_extrusion_layer.hpp28
-rw-r--r--include/mbgl/style/layers/fill_layer.hpp28
-rw-r--r--include/mbgl/style/layers/layer.hpp.ejs16
-rw-r--r--include/mbgl/style/layers/line_layer.hpp43
-rw-r--r--include/mbgl/style/layers/raster_layer.hpp10
-rw-r--r--include/mbgl/style/layers/symbol_layer.hpp101
-rw-r--r--include/mbgl/style/property_value.hpp26
-rw-r--r--include/mbgl/style/undefined.hpp12
-rw-r--r--include/mbgl/util/chrono.hpp2
-rw-r--r--include/mbgl/util/compression.hpp4
-rw-r--r--include/mbgl/util/constants.hpp4
-rw-r--r--include/mbgl/util/feature.hpp17
-rw-r--r--include/mbgl/util/geo.hpp8
-rw-r--r--include/mbgl/util/image.hpp72
-rw-r--r--include/mbgl/util/size.hpp4
m---------mapbox-gl-js0
-rw-r--r--package.json5
-rw-r--r--platform/android/CHANGELOG.md61
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle39
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle5
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle4
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-publish.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java30
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java311
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java231
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java33
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java116
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java62
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java95
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java213
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java148
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java65
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java109
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java187
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java31
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java589
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java85
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java68
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java43
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java129
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java135
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java54
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java50
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java99
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java300
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java84
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java64
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java58
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java109
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java99
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java6
-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.java48
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java137
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java56
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java299
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java1223
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java124
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/UnknownLayer.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs242
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs80
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs180
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/NoSuchSourceException.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java58
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java161
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java828
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java70
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java156
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java66
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_popup_window_transparent.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml95
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_view.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml190
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle53
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-make.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerStyleTest.java141
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java149
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerStyleTest.java265
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java1135
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerStyleTest.java286
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java595
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerStyleTest.java427
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java1097
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerStyleTest.java240
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java316
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleBackgroundLayerTest.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java269
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerStyleTest.java1283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java3107
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs367
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml348
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AddRemoveMarkerActivity.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java103
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java77
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java179
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewsInRectangleActivity.java32
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java28
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java55
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java25
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java5
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java42
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java213
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java55
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MapFragmentActivity.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/SupportMapFragmentActivity.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java27
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java205
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java27
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java67
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java36
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java32
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java25
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java26
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/CarDrivingActivity.java201
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java477
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java168
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/UpdateMetadataActivity.java23
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java395
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java44
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java30
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java150
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java33
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java43
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java93
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java108
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java5
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ToolbarComposer.java49
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/rotate_360.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android.pngbin0 -> 1711 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android_2.pngbin0 -> 1562 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.pngbin2829 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android.pngbin0 -> 1217 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android_2.pngbin0 -> 1117 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.pngbin2820 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android.pngbin0 -> 2202 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android_2.pngbin0 -> 2142 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.pngbin2836 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android.pngbin0 -> 3639 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android_2.pngbin0 -> 3495 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.pngbin1178 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.pngbin1692 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.pngbin202 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android.pngbin0 -> 4936 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android_2.pngbin0 -> 4883 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top_small.pngbin10087 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh.xml (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh_24dp.xml)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_stars.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/marker.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_remove_marker.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml46
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_car_driving.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circlelayer.xml36
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml50
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_data_driven_style.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml88
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml66
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_source.xml36
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml20
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml25
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml25
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_in_rect.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml61
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_metadata_update.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml45
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polygon.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml16
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml58
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml14
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml22
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml19
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_video_view.xml37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml20
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_visible_bounds.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml25
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bulk_marker.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_data_driven_style.xml50
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/sea_waves.mp4bin5166670 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml22
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml132
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java67
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java21
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java31
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java10
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/ExponentialBackOffTest.java19
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle34
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/gradle-config.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/AndroidManifest.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/FeatureOverviewActivity.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleWearMapActivity.java (renamed from platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleMapViewActivity.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/adapter/FeatureAdapter.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/utils/OffsettingHelper.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_feature_overview.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/item_curved_layout.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/values/colors.xml2
-rw-r--r--platform/android/bitrise.yml45
-rw-r--r--platform/android/build.gradle5
-rw-r--r--platform/android/checkstyle.xml8
-rw-r--r--platform/android/config.cmake114
-rw-r--r--platform/android/dependencies.gradle55
-rwxr-xr-xplatform/android/scripts/debug.sh24
-rw-r--r--platform/android/scripts/generate-style-code.js42
-rwxr-xr-xplatform/android/scripts/ndk.sh111
-rw-r--r--platform/android/scripts/release.py2
-rwxr-xr-xplatform/android/scripts/toolchain.sh23
-rw-r--r--platform/android/src/annotation/marker.cpp31
-rw-r--r--platform/android/src/annotation/marker.hpp30
-rw-r--r--platform/android/src/annotation/multi_point.hpp42
-rw-r--r--platform/android/src/annotation/polygon.cpp49
-rw-r--r--platform/android/src/annotation/polygon.hpp40
-rw-r--r--platform/android/src/annotation/polyline.cpp49
-rw-r--r--platform/android/src/annotation/polyline.hpp40
-rw-r--r--platform/android/src/bitmap.cpp132
-rw-r--r--platform/android/src/bitmap.hpp52
-rw-r--r--platform/android/src/bitmap_factory.cpp25
-rw-r--r--platform/android/src/bitmap_factory.hpp25
-rw-r--r--platform/android/src/connectivity_listener.cpp8
-rw-r--r--platform/android/src/connectivity_listener.hpp8
-rw-r--r--platform/android/src/conversion/collection.hpp14
-rw-r--r--platform/android/src/conversion/color.hpp24
-rw-r--r--platform/android/src/conversion/constant.hpp2
-rw-r--r--platform/android/src/conversion/conversion.hpp2
-rw-r--r--platform/android/src/file_source.cpp106
-rw-r--r--platform/android/src/file_source.hpp53
-rw-r--r--platform/android/src/geometry/conversion/feature.hpp66
-rw-r--r--platform/android/src/geometry/conversion/geometry.hpp14
-rw-r--r--platform/android/src/geometry/feature.cpp20
-rw-r--r--platform/android/src/geometry/feature.hpp29
-rw-r--r--platform/android/src/geometry/geometry.hpp16
-rw-r--r--platform/android/src/geometry/lat_lng.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng.hpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.cpp31
-rw-r--r--platform/android/src/geometry/lat_lng_bounds.hpp29
-rw-r--r--platform/android/src/geometry/projected_meters.cpp20
-rw-r--r--platform/android/src/geometry/projected_meters.hpp26
-rw-r--r--platform/android/src/graphics/pointf.cpp20
-rw-r--r--platform/android/src/graphics/pointf.hpp25
-rw-r--r--platform/android/src/graphics/rectf.cpp35
-rw-r--r--platform/android/src/graphics/rectf.hpp31
-rw-r--r--platform/android/src/gson/json_object.hpp16
-rw-r--r--platform/android/src/image.cpp22
-rw-r--r--platform/android/src/java/lang.hpp21
-rw-r--r--platform/android/src/java/util.cpp18
-rw-r--r--platform/android/src/java/util.hpp33
-rw-r--r--platform/android/src/java_types.hpp2
-rwxr-xr-xplatform/android/src/jni.cpp2049
-rw-r--r--platform/android/src/jni.hpp14
-rw-r--r--platform/android/src/jni/generic_global_ref_deleter.hpp22
-rwxr-xr-xplatform/android/src/native_map_view.cpp1304
-rwxr-xr-xplatform/android/src/native_map_view.hpp268
-rw-r--r--platform/android/src/offline/offline_manager.cpp164
-rw-r--r--platform/android/src/offline/offline_manager.hpp75
-rw-r--r--platform/android/src/offline/offline_region.cpp308
-rw-r--r--platform/android/src/offline/offline_region.hpp99
-rw-r--r--platform/android/src/offline/offline_region_definition.cpp69
-rw-r--r--platform/android/src/offline/offline_region_definition.hpp34
-rw-r--r--platform/android/src/offline/offline_region_error.cpp53
-rw-r--r--platform/android/src/offline/offline_region_error.hpp21
-rw-r--r--platform/android/src/offline/offline_region_status.cpp39
-rw-r--r--platform/android/src/offline/offline_region_status.hpp21
-rw-r--r--platform/android/src/style/android_conversion.hpp5
-rw-r--r--platform/android/src/style/conversion/function.hpp211
-rw-r--r--platform/android/src/style/conversion/geojson.hpp4
-rw-r--r--platform/android/src/style/conversion/property_value.hpp67
-rw-r--r--platform/android/src/style/conversion/types.hpp2
-rw-r--r--platform/android/src/style/conversion/types.hpp.ejs2
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp24
-rw-r--r--platform/android/src/style/conversion/types_string_values.hpp.ejs6
-rw-r--r--platform/android/src/style/conversion/url_or_tileset.hpp2
-rw-r--r--platform/android/src/style/functions/categorical_stops.cpp18
-rw-r--r--platform/android/src/style/functions/categorical_stops.hpp23
-rw-r--r--platform/android/src/style/functions/exponential_stops.cpp18
-rw-r--r--platform/android/src/style/functions/exponential_stops.hpp24
-rw-r--r--platform/android/src/style/functions/identity_stops.cpp18
-rw-r--r--platform/android/src/style/functions/identity_stops.hpp21
-rw-r--r--platform/android/src/style/functions/interval_stops.cpp18
-rw-r--r--platform/android/src/style/functions/interval_stops.hpp23
-rw-r--r--platform/android/src/style/functions/stop.cpp21
-rw-r--r--platform/android/src/style/functions/stop.hpp36
-rw-r--r--platform/android/src/style/layers/background_layer.cpp17
-rw-r--r--platform/android/src/style/layers/background_layer.hpp2
-rw-r--r--platform/android/src/style/layers/circle_layer.cpp17
-rw-r--r--platform/android/src/style/layers/circle_layer.hpp2
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp4
-rw-r--r--platform/android/src/style/layers/fill_layer.cpp17
-rw-r--r--platform/android/src/style/layers/fill_layer.hpp2
-rw-r--r--platform/android/src/style/layers/layer.cpp35
-rw-r--r--platform/android/src/style/layers/layer.cpp.ejs20
-rw-r--r--platform/android/src/style/layers/layer.hpp27
-rw-r--r--platform/android/src/style/layers/layer.hpp.ejs2
-rw-r--r--platform/android/src/style/layers/layers.cpp64
-rw-r--r--platform/android/src/style/layers/layers.hpp12
-rw-r--r--platform/android/src/style/layers/line_layer.cpp17
-rw-r--r--platform/android/src/style/layers/line_layer.hpp2
-rw-r--r--platform/android/src/style/layers/raster_layer.cpp17
-rw-r--r--platform/android/src/style/layers/raster_layer.hpp2
-rw-r--r--platform/android/src/style/layers/symbol_layer.cpp17
-rw-r--r--platform/android/src/style/layers/symbol_layer.hpp2
-rw-r--r--platform/android/src/style/layers/unknown_layer.cpp49
-rw-r--r--platform/android/src/style/layers/unknown_layer.hpp30
-rw-r--r--platform/android/src/style/sources/geojson_source.cpp10
-rw-r--r--platform/android/src/style/sources/raster_source.cpp4
-rw-r--r--platform/android/src/style/sources/source.cpp18
-rw-r--r--platform/android/src/style/sources/source.hpp16
-rw-r--r--platform/android/src/style/sources/sources.cpp10
-rw-r--r--platform/android/src/style/sources/sources.hpp8
-rw-r--r--platform/android/src/style/sources/unknown_source.cpp42
-rw-r--r--platform/android/src/style/sources/unknown_source.hpp28
-rw-r--r--platform/android/src/style/sources/vector_source.cpp4
-rw-r--r--platform/android/src/style/value.cpp2
-rw-r--r--platform/android/src/test/Main.java6
-rw-r--r--platform/android/src/test/main.jni.cpp59
-rw-r--r--platform/android/src/timer.cpp2
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs19
-rw-r--r--platform/darwin/docs/theme/assets/css/jazzy.css.scss1
-rw-r--r--platform/darwin/mbgl/storage/reachability.h2
-rw-r--r--platform/darwin/mbgl/storage/reachability.m8
-rw-r--r--platform/darwin/mbgl/util/image+MGLAdditions.hpp12
-rw-r--r--platform/darwin/resources/de.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/de.lproj/Foundation.stringsdict38
-rw-r--r--platform/darwin/resources/es.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/fr.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/ja.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/pl.lproj/Foundation.stringsdict60
-rw-r--r--platform/darwin/resources/pt-BR.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/ru.lproj/Foundation.stringsdict60
-rw-r--r--platform/darwin/resources/sv.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/sv.lproj/Foundation.stringsdict54
-rw-r--r--platform/darwin/resources/uk.lproj/Foundation.stringsdict60
-rw-r--r--platform/darwin/resources/vi.lproj/Foundation.strings291
-rw-r--r--platform/darwin/resources/zh-Hant.lproj/Foundation.strings291
-rw-r--r--platform/darwin/scripts/generate-style-code.js43
-rw-r--r--platform/darwin/scripts/update-examples.js32
-rw-r--r--platform/darwin/src/MGLAccountManager.h6
-rw-r--r--platform/darwin/src/MGLAccountManager.m2
-rw-r--r--platform/darwin/src/MGLAnnotation.h6
-rw-r--r--platform/darwin/src/MGLAttributionInfo.h8
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm20
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h6
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.h29
-rw-r--r--platform/darwin/src/MGLBackgroundStyleLayer.mm26
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h192
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.mm89
-rw-r--r--platform/darwin/src/MGLClockDirectionFormatter.h6
-rw-r--r--platform/darwin/src/MGLClockDirectionFormatter.m8
-rw-r--r--platform/darwin/src/MGLCompassDirectionFormatter.h6
-rw-r--r--platform/darwin/src/MGLCompassDirectionFormatter.m20
-rw-r--r--platform/darwin/src/MGLConversion.h135
-rw-r--r--platform/darwin/src/MGLCoordinateFormatter.h8
-rw-r--r--platform/darwin/src/MGLCoordinateFormatter.m16
-rw-r--r--platform/darwin/src/MGLDistanceFormatter.h26
-rw-r--r--platform/darwin/src/MGLDistanceFormatter.m35
-rw-r--r--platform/darwin/src/MGLFeature.h72
-rw-r--r--platform/darwin/src/MGLFeature.mm30
-rw-r--r--platform/darwin/src/MGLFeature_Private.h2
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h122
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.mm58
-rw-r--r--platform/darwin/src/MGLForegroundStyleLayer.h6
-rw-r--r--platform/darwin/src/MGLFoundation.mm4
-rw-r--r--platform/darwin/src/MGLFoundation_Private.h5
-rw-r--r--platform/darwin/src/MGLGeometry.h2
-rw-r--r--platform/darwin/src/MGLGeometry.mm2
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h4
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h183
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm107
-rw-r--r--platform/darwin/src/MGLMapCamera.h20
-rw-r--r--platform/darwin/src/MGLMapCamera.mm27
-rw-r--r--platform/darwin/src/MGLMultiPoint.h30
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm10
-rw-r--r--platform/darwin/src/MGLNetworkConfiguration.h10
-rw-r--r--platform/darwin/src/MGLOfflinePack.h32
-rw-r--r--platform/darwin/src/MGLOfflinePack.mm77
-rw-r--r--platform/darwin/src/MGLOfflinePack_Private.h54
-rw-r--r--platform/darwin/src/MGLOfflineRegion_Private.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h106
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm97
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm44
-rw-r--r--platform/darwin/src/MGLOverlay.h8
-rw-r--r--platform/darwin/src/MGLPointAnnotation.h8
-rw-r--r--platform/darwin/src/MGLPointAnnotation.mm2
-rw-r--r--platform/darwin/src/MGLPointCollection.h10
-rw-r--r--platform/darwin/src/MGLPointCollection.mm4
-rw-r--r--platform/darwin/src/MGLPolygon+MGLAdditions.m6
-rw-r--r--platform/darwin/src/MGLPolygon.h24
-rw-r--r--platform/darwin/src/MGLPolygon.mm10
-rw-r--r--platform/darwin/src/MGLPolyline.h20
-rw-r--r--platform/darwin/src/MGLPolyline.mm12
-rw-r--r--platform/darwin/src/MGLRasterSource.h24
-rw-r--r--platform/darwin/src/MGLRasterSource.mm17
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h57
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.mm58
-rw-r--r--platform/darwin/src/MGLShape.h28
-rw-r--r--platform/darwin/src/MGLShape.mm4
-rw-r--r--platform/darwin/src/MGLShapeCollection.h12
-rw-r--r--platform/darwin/src/MGLShapeCollection.mm2
-rw-r--r--platform/darwin/src/MGLShapeSource.h103
-rw-r--r--platform/darwin/src/MGLShapeSource.mm28
-rw-r--r--platform/darwin/src/MGLSource.h8
-rw-r--r--platform/darwin/src/MGLSource_Private.h14
-rw-r--r--platform/darwin/src/MGLStyle.h100
-rw-r--r--platform/darwin/src/MGLStyle.mm8
-rw-r--r--platform/darwin/src/MGLStyleLayer.h13
-rw-r--r--platform/darwin/src/MGLStyleLayer.h.ejs12
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm2
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs65
-rw-r--r--platform/darwin/src/MGLStyleLayer_Private.h4
-rw-r--r--platform/darwin/src/MGLStyleValue.h386
-rw-r--r--platform/darwin/src/MGLStyleValue.mm254
-rw-r--r--platform/darwin/src/MGLStyleValue_Private.h661
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h581
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.mm333
-rw-r--r--platform/darwin/src/MGLTilePyramidOfflineRegion.h12
-rw-r--r--platform/darwin/src/MGLTilePyramidOfflineRegion.mm8
-rw-r--r--platform/darwin/src/MGLTileSource.h46
-rw-r--r--platform/darwin/src/MGLTileSource.mm14
-rw-r--r--platform/darwin/src/MGLTileSource_Private.h4
-rw-r--r--platform/darwin/src/MGLValueEvaluator.h14
-rw-r--r--platform/darwin/src/MGLVectorSource.h8
-rw-r--r--platform/darwin/src/MGLVectorSource.mm15
-rw-r--r--platform/darwin/src/MGLVectorStyleLayer.h40
-rw-r--r--platform/darwin/src/NSArray+MGLAdditions.mm6
-rw-r--r--platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm113
-rw-r--r--platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm10
-rw-r--r--platform/darwin/src/NSData+MGLAdditions.mm4
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.h3
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm75
-rw-r--r--platform/darwin/src/NSPredicate+MGLAdditions.mm112
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h2
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m2
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h8
-rw-r--r--platform/darwin/src/headless_display_cgl.cpp12
-rw-r--r--platform/darwin/src/http_file_source.mm27
-rw-r--r--platform/darwin/src/image.mm173
-rw-r--r--platform/darwin/src/run_loop.cpp17
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m26
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.mm121
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm540
-rw-r--r--platform/darwin/test/MGLClockDirectionFormatterTests.m26
-rw-r--r--platform/darwin/test/MGLCodingTests.m200
-rw-r--r--platform/darwin/test/MGLCompassDirectionFormatterTests.m32
-rw-r--r--platform/darwin/test/MGLCoordinateFormatterTests.m16
-rw-r--r--platform/darwin/test/MGLDistanceFormatterTests.m30
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift37
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm240
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm80
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.mm343
-rw-r--r--platform/darwin/test/MGLGeometryTests.mm64
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm656
-rw-r--r--platform/darwin/test/MGLNSStringAdditionsTests.m18
-rw-r--r--platform/darwin/test/MGLOfflinePackTests.m6
-rw-r--r--platform/darwin/test/MGLOfflineRegionTests.m4
-rw-r--r--platform/darwin/test/MGLOfflineStorageTests.mm (renamed from platform/darwin/test/MGLOfflineStorageTests.m)92
-rw-r--r--platform/darwin/test/MGLPredicateTests.mm249
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.mm279
-rw-r--r--platform/darwin/test/MGLShapeSourceTests.mm76
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m10
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs79
-rw-r--r--platform/darwin/test/MGLStyleTests.mm149
-rw-r--r--platform/darwin/test/MGLStyleValueTests.m102
-rw-r--r--platform/darwin/test/MGLStyleValueTests.swift289
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm2116
-rw-r--r--platform/darwin/test/MGLTileSetTests.mm26
-rw-r--r--platform/default/bidi.cpp17
-rw-r--r--platform/default/default_file_source.cpp41
-rw-r--r--platform/default/headless_backend_osmesa.cpp3
-rw-r--r--platform/default/image.cpp70
-rw-r--r--platform/default/jpeg_reader.cpp4
-rw-r--r--platform/default/local_file_source.cpp6
-rw-r--r--platform/default/mbgl/gl/headless_backend.cpp29
-rw-r--r--platform/default/mbgl/gl/headless_backend.hpp11
-rw-r--r--platform/default/mbgl/gl/offscreen_view.cpp60
-rw-r--r--platform/default/mbgl/gl/offscreen_view.hpp13
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp23
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp2
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp4
-rw-r--r--platform/default/mbgl/storage/offline_download.hpp2
-rw-r--r--platform/default/mbgl/util/default_thread_pool.cpp6
-rw-r--r--platform/default/mbgl/util/shared_thread_pool.cpp14
-rw-r--r--platform/default/mbgl/util/shared_thread_pool.hpp9
-rw-r--r--platform/default/online_file_source.cpp30
-rw-r--r--platform/default/png_reader.cpp18
-rw-r--r--platform/default/png_writer.cpp80
-rw-r--r--platform/default/sqlite3.cpp283
-rw-r--r--platform/default/sqlite3.hpp31
-rw-r--r--platform/glfw/glfw_view.cpp15
-rw-r--r--platform/glfw/glfw_view.hpp8
-rw-r--r--platform/glfw/main.cpp12
-rw-r--r--platform/ios/CHANGELOG.md49
-rw-r--r--platform/ios/DEVELOPING.md25
-rw-r--r--platform/ios/INSTALL.md6
-rw-r--r--platform/ios/Mapbox-iOS-SDK-static-part.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/README.md2
-rw-r--r--platform/ios/app/Base.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/MBXAnnotationView.m8
-rw-r--r--platform/ios/app/MBXCustomCalloutView.m14
-rw-r--r--platform/ios/app/MBXOfflinePacksTableViewController.m54
-rw-r--r--platform/ios/app/MBXUserLocationAnnotationView.m28
-rw-r--r--platform/ios/app/MBXViewController.m350
-rw-r--r--platform/ios/app/de.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/es.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/fr.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/ja.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/lt.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/pl.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/pt-BR.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/ru.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/sv.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/uk.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/vi.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/zh-Hans.lproj/Localizable.strings0
-rw-r--r--platform/ios/app/zh-Hant.lproj/Localizable.strings0
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.mm8
-rw-r--r--platform/ios/config.cmake4
-rw-r--r--platform/ios/docs/doc-README.md2
-rw-r--r--platform/ios/docs/guides/For Style Authors.md14
-rw-r--r--platform/ios/docs/guides/Gesture Recognizers.md38
-rw-r--r--platform/ios/docs/img/user-interaction/RotateSydney.gifbin0 -> 693038 bytes
-rw-r--r--platform/ios/docs/img/user-interaction/quickzoom.gifbin0 -> 793787 bytes
-rw-r--r--platform/ios/docs/pod-README.md6
-rw-r--r--platform/ios/framework/Settings.bundle/de.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/es.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/fr.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/lt.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/pl.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/pt-BR.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/ru.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/sv.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/uk.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/vi.lproj/Root.strings3
-rw-r--r--platform/ios/framework/Settings.bundle/zh-Hant.lproj/Root.strings3
-rwxr-xr-xplatform/ios/framework/strip-frameworks.sh19
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj176
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme2
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/static.xcscheme2
-rw-r--r--platform/ios/jazzy.yml2
-rw-r--r--platform/ios/resources/de.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/de.lproj/Localizable.stringsdict23
-rw-r--r--platform/ios/resources/es.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/fr.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/fr.lproj/Localizable.stringsdict23
-rw-r--r--platform/ios/resources/ja.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/lt.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/pt-BR.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/pt-BR.lproj/Localizable.stringsdict23
-rw-r--r--platform/ios/resources/ru.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/sv.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/uk.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/vi.lproj/Localizable.strings75
-rw-r--r--platform/ios/resources/zh-Hant.lproj/Localizable.strings84
-rwxr-xr-xplatform/ios/scripts/deploy-packages.sh12
-rwxr-xr-xplatform/ios/scripts/package.sh10
-rwxr-xr-xplatform/ios/scripts/release-fabric.sh4
-rwxr-xr-xplatform/ios/scripts/validate-fabric-zip.sh20
-rw-r--r--platform/ios/src/MGLAPIClient.m26
-rw-r--r--platform/ios/src/MGLAnnotationImage.h10
-rw-r--r--platform/ios/src/MGLAnnotationImage.m4
-rw-r--r--platform/ios/src/MGLAnnotationView.h46
-rw-r--r--platform/ios/src/MGLAnnotationView.mm14
-rw-r--r--platform/ios/src/MGLCalloutView.h2
-rw-r--r--platform/ios/src/MGLCompactCalloutView.m2
-rw-r--r--platform/ios/src/MGLFaux3DUserLocationAnnotationView.m28
-rw-r--r--platform/ios/src/MGLLocationManager.m15
-rw-r--r--platform/ios/src/MGLMapView.h327
-rw-r--r--platform/ios/src/MGLMapView.mm442
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h182
-rw-r--r--platform/ios/src/MGLMapboxEvents.m78
-rw-r--r--platform/ios/src/MGLUserLocation.h6
-rw-r--r--platform/ios/src/MGLUserLocation.m2
-rw-r--r--platform/ios/src/MGLUserLocationAnnotationView.h8
-rw-r--r--platform/ios/src/MGLUserLocationAnnotationView.m10
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/ios/src/UIImage+MGLAdditions.mm35
-rw-r--r--platform/ios/test/MGLAnnotationViewTests.m8
-rw-r--r--platform/ios/test/MGLNSDataAdditionsTests.m12
-rw-r--r--platform/ios/test/MGLSourceTests.m4
-rw-r--r--platform/ios/uitest/MapViewTests.m54
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMArg.h2
-rw-r--r--platform/ios/uitest/OCMock/OCMock/OCMConstraint.h2
-rw-r--r--platform/ios/uitest/ios-tests.xcodeproj/xcshareddata/xcschemes/Mapbox GL Tests.xcscheme2
-rw-r--r--platform/ios/vendor/Fabric/Fabric+FABKits.h2
-rw-r--r--platform/linux/config.cmake39
-rwxr-xr-xplatform/linux/scripts/coveralls.sh5
-rw-r--r--platform/linux/src/headless_backend_egl.cpp3
-rw-r--r--platform/macos/CHANGELOG.md42
-rw-r--r--platform/macos/DEVELOPING.md21
-rw-r--r--platform/macos/INSTALL.md8
-rw-r--r--platform/macos/Mapbox-macOS-SDK-symbols.podspec2
-rw-r--r--platform/macos/Mapbox-macOS-SDK.podspec2
-rw-r--r--platform/macos/README.md18
-rw-r--r--platform/macos/app/AppDelegate.m50
-rw-r--r--platform/macos/app/Base.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/Base.lproj/MainMenu.xib8
-rw-r--r--platform/macos/app/Base.lproj/MapDocument.xib11
-rw-r--r--platform/macos/app/DroppedPinAnnotation.m2
-rw-r--r--platform/macos/app/Info.plist2
-rw-r--r--platform/macos/app/LimeGreenStyleLayer.m8
-rw-r--r--platform/macos/app/MGLVectorSource+MBXAdditions.m2
-rw-r--r--platform/macos/app/MapDocument.m116
-rw-r--r--platform/macos/app/OfflinePackNameValueTransformer.m4
-rw-r--r--platform/macos/app/StyleLayerIconTransformer.m2
-rw-r--r--platform/macos/app/TimeIntervalTransformer.m6
-rw-r--r--platform/macos/app/de.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/es.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/fr.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/ja.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/lt.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/pl.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/pt-BR.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/sv.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/uk.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/vi.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/zh-Hans.lproj/Localizable.strings0
-rw-r--r--platform/macos/app/zh-Hant.lproj/Localizable.strings0
-rw-r--r--platform/macos/config.cmake10
-rw-r--r--platform/macos/docs/guides/For Style Authors.md11
-rw-r--r--platform/macos/docs/pod-README.md6
-rw-r--r--platform/macos/jazzy.yml1
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj125
-rwxr-xr-xplatform/macos/scripts/deploy-packages.sh14
-rw-r--r--platform/macos/sdk/de.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/es.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/fr.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/ja.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/lt.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/pl.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/pt-BR.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/sv.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/uk.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/vi.lproj/Localizable.strings15
-rw-r--r--platform/macos/sdk/zh-Hant.lproj/Localizable.strings15
-rw-r--r--platform/macos/src/MGLAnnotationImage.h10
-rw-r--r--platform/macos/src/MGLAnnotationImage.m4
-rw-r--r--platform/macos/src/MGLAttributionButton.mm10
-rw-r--r--platform/macos/src/MGLMapView+IBAdditions.h2
-rw-r--r--platform/macos/src/MGLMapView.h253
-rw-r--r--platform/macos/src/MGLMapView.mm208
-rw-r--r--platform/macos/src/MGLMapViewDelegate.h96
-rw-r--r--platform/macos/src/MGLOpenGLLayer.mm17
-rw-r--r--platform/macos/src/Mapbox.h1
-rw-r--r--platform/macos/src/NSColor+MGLAdditions.mm4
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.h2
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.mm23
-rw-r--r--platform/macos/test/MGLAttributionButtonTests.m4
-rw-r--r--platform/node/bitrise.yml2
-rw-r--r--platform/node/index.js2
-rw-r--r--platform/node/src/node_map.cpp40
-rw-r--r--platform/node/test/js/require.js2
-rw-r--r--platform/node/test/memory.test.js4
-rw-r--r--platform/qt/app/mapwindow.cpp79
-rw-r--r--platform/qt/app/mapwindow.hpp5
-rw-r--r--platform/qt/config.cmake4
-rw-r--r--platform/qt/config.qdocconf3
-rw-r--r--platform/qt/include/QQuickMapboxGL1
-rw-r--r--platform/qt/include/QQuickMapboxGLMapParameter1
-rw-r--r--platform/qt/include/qmapbox.hpp74
-rw-r--r--platform/qt/include/qmapboxgl.hpp20
-rw-r--r--platform/qt/include/qquickmapboxgl.hpp (renamed from platform/qt/src/qquickmapboxgl.hpp)0
-rw-r--r--platform/qt/include/qquickmapboxglmapparameter.hpp (renamed from platform/qt/src/qquickmapboxglmapparameter.hpp)0
-rw-r--r--platform/qt/qmlapp/main.cpp8
-rw-r--r--platform/qt/qt.cmake6
-rw-r--r--platform/qt/qt4.cmake1
-rw-r--r--platform/qt/qt5.cmake9
-rw-r--r--platform/qt/resources/common.qrc1
-rw-r--r--platform/qt/src/http_file_source.cpp2
-rw-r--r--platform/qt/src/http_request.cpp2
-rw-r--r--platform/qt/src/qmapbox.cpp237
-rw-r--r--platform/qt/src/qmapboxgl.cpp163
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp6
-rw-r--r--platform/qt/src/qquickmapboxglrenderer.cpp4
-rw-r--r--platform/qt/src/qt_conversion.hpp10
-rw-r--r--platform/qt/src/qt_geojson.hpp180
-rw-r--r--platform/qt/src/sqlite3.cpp436
-rwxr-xr-xscripts/build-shaders.js60
-rwxr-xr-xscripts/build-version.js81
-rwxr-xr-xscripts/clang-tools.sh6
-rwxr-xr-xscripts/codestyle.sh37
-rwxr-xr-xscripts/generate-shaders.js100
-rw-r--r--scripts/generate-style-code.js60
-rwxr-xr-xscripts/log_memory_benchmarks.sh39
-rwxr-xr-xscripts/mason.sh3
-rwxr-xr-xscripts/travis_setup.sh21
-rwxr-xr-xscripts/update_ca_bundle.sh5
-rwxr-xr-xscripts/valgrind.sh6
-rw-r--r--scripts/valgrind.sup71
-rw-r--r--src/mbgl/annotation/annotation_manager.cpp4
-rw-r--r--src/mbgl/gl/attribute.cpp227
-rw-r--r--src/mbgl/gl/attribute.hpp185
-rw-r--r--src/mbgl/gl/context.cpp92
-rw-r--r--src/mbgl/gl/context.hpp41
-rw-r--r--src/mbgl/gl/debugging.cpp2
-rw-r--r--src/mbgl/gl/draw_mode.hpp19
-rw-r--r--src/mbgl/gl/normalization.hpp35
-rw-r--r--src/mbgl/gl/program.hpp42
-rw-r--r--src/mbgl/gl/segment.cpp7
-rw-r--r--src/mbgl/gl/segment.hpp43
-rw-r--r--src/mbgl/gl/types.hpp10
-rw-r--r--src/mbgl/gl/uniform.hpp33
-rw-r--r--src/mbgl/gl/vertex_array.hpp2
-rw-r--r--src/mbgl/layout/symbol_feature.hpp16
-rw-r--r--src/mbgl/layout/symbol_instance.cpp46
-rw-r--r--src/mbgl/layout/symbol_instance.hpp9
-rw-r--r--src/mbgl/layout/symbol_layout.cpp353
-rw-r--r--src/mbgl/layout/symbol_layout.hpp35
-rw-r--r--src/mbgl/map/backend_scope.cpp36
-rw-r--r--src/mbgl/map/map.cpp93
-rw-r--r--src/mbgl/map/transform.cpp80
-rw-r--r--src/mbgl/map/transform.hpp40
-rw-r--r--src/mbgl/programs/attributes.hpp206
-rw-r--r--src/mbgl/programs/circle_program.cpp2
-rw-r--r--src/mbgl/programs/circle_program.hpp34
-rw-r--r--src/mbgl/programs/collision_box_program.cpp2
-rw-r--r--src/mbgl/programs/collision_box_program.hpp23
-rw-r--r--src/mbgl/programs/debug_program.hpp14
-rw-r--r--src/mbgl/programs/fill_program.cpp8
-rw-r--r--src/mbgl/programs/fill_program.hpp72
-rw-r--r--src/mbgl/programs/line_program.cpp14
-rw-r--r--src/mbgl/programs/line_program.hpp90
-rw-r--r--src/mbgl/programs/program.hpp56
-rw-r--r--src/mbgl/programs/programs.hpp4
-rw-r--r--src/mbgl/programs/raster_program.cpp2
-rw-r--r--src/mbgl/programs/raster_program.hpp29
-rw-r--r--src/mbgl/programs/symbol_program.cpp90
-rw-r--r--src/mbgl/programs/symbol_program.hpp109
-rw-r--r--src/mbgl/renderer/bucket.hpp7
-rw-r--r--src/mbgl/renderer/circle_bucket.cpp29
-rw-r--r--src/mbgl/renderer/circle_bucket.hpp20
-rw-r--r--src/mbgl/renderer/debug_bucket.cpp4
-rw-r--r--src/mbgl/renderer/debug_bucket.hpp2
-rw-r--r--src/mbgl/renderer/fill_bucket.cpp30
-rw-r--r--src/mbgl/renderer/fill_bucket.hpp20
-rw-r--r--src/mbgl/renderer/frame_history.cpp2
-rw-r--r--src/mbgl/renderer/frame_history.hpp2
-rw-r--r--src/mbgl/renderer/line_bucket.cpp55
-rw-r--r--src/mbgl/renderer/line_bucket.hpp25
-rw-r--r--src/mbgl/renderer/painter.cpp26
-rw-r--r--src/mbgl/renderer/painter.hpp4
-rw-r--r--src/mbgl/renderer/painter_background.cpp33
-rw-r--r--src/mbgl/renderer/painter_circle.cpp12
-rw-r--r--src/mbgl/renderer/painter_clipping.cpp10
-rw-r--r--src/mbgl/renderer/painter_debug.cpp10
-rw-r--r--src/mbgl/renderer/painter_fill.cpp46
-rw-r--r--src/mbgl/renderer/painter_line.cpp11
-rw-r--r--src/mbgl/renderer/painter_raster.cpp6
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp55
-rw-r--r--src/mbgl/renderer/symbol_bucket.cpp22
-rw-r--r--src/mbgl/renderer/symbol_bucket.hpp22
-rw-r--r--src/mbgl/shaders/circle.cpp191
-rw-r--r--src/mbgl/shaders/circle.hpp16
-rw-r--r--src/mbgl/shaders/collision_box.cpp128
-rw-r--r--src/mbgl/shaders/collision_box.hpp16
-rw-r--r--src/mbgl/shaders/debug.cpp100
-rw-r--r--src/mbgl/shaders/debug.hpp16
-rw-r--r--src/mbgl/shaders/fill.cpp120
-rw-r--r--src/mbgl/shaders/fill.hpp16
-rw-r--r--src/mbgl/shaders/fill_outline.cpp128
-rw-r--r--src/mbgl/shaders/fill_outline.hpp16
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.cpp156
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.hpp16
-rw-r--r--src/mbgl/shaders/fill_pattern.cpp145
-rw-r--r--src/mbgl/shaders/fill_pattern.hpp16
-rw-r--r--src/mbgl/shaders/line.cpp216
-rw-r--r--src/mbgl/shaders/line.hpp16
-rw-r--r--src/mbgl/shaders/line_pattern.cpp233
-rw-r--r--src/mbgl/shaders/line_pattern.hpp16
-rw-r--r--src/mbgl/shaders/line_sdf.cpp239
-rw-r--r--src/mbgl/shaders/line_sdf.hpp16
-rw-r--r--src/mbgl/shaders/raster.cpp150
-rw-r--r--src/mbgl/shaders/raster.hpp16
-rw-r--r--src/mbgl/shaders/symbol_icon.cpp151
-rw-r--r--src/mbgl/shaders/symbol_icon.hpp16
-rw-r--r--src/mbgl/shaders/symbol_sdf.cpp242
-rw-r--r--src/mbgl/shaders/symbol_sdf.hpp16
-rw-r--r--src/mbgl/sprite/sprite_atlas.cpp273
-rw-r--r--src/mbgl/sprite/sprite_atlas.hpp77
-rw-r--r--src/mbgl/sprite/sprite_parser.cpp11
-rw-r--r--src/mbgl/storage/local_file_source.hpp2
-rw-r--r--src/mbgl/style/bucket_parameters.cpp14
-rw-r--r--src/mbgl/style/bucket_parameters.hpp21
-rw-r--r--src/mbgl/style/conversion/stringify.hpp240
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.cpp19
-rw-r--r--src/mbgl/style/cross_faded_property_evaluator.hpp2
-rw-r--r--src/mbgl/style/data_driven_property_evaluator.hpp42
-rw-r--r--src/mbgl/style/function.cpp81
-rw-r--r--src/mbgl/style/function/categorical_stops.cpp38
-rw-r--r--src/mbgl/style/function/identity_stops.cpp61
-rw-r--r--src/mbgl/style/layer_impl.hpp2
-rw-r--r--src/mbgl/style/layer_observer.hpp1
-rw-r--r--src/mbgl/style/layers/background_layer.cpp12
-rw-r--r--src/mbgl/style/layers/background_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/background_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/background_layer_properties.hpp1
-rw-r--r--src/mbgl/style/layers/circle_layer.cpp124
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.cpp25
-rw-r--r--src/mbgl/style/layers/circle_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/circle_layer_properties.hpp15
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/custom_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer.cpp64
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.cpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_extrusion_layer_properties.hpp7
-rw-r--r--src/mbgl/style/layers/fill_layer.cpp64
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp21
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/fill_layer_properties.hpp7
-rw-r--r--src/mbgl/style/layers/layer.cpp.ejs24
-rw-r--r--src/mbgl/style/layers/layer_properties.hpp.ejs11
-rw-r--r--src/mbgl/style/layers/line_layer.cpp100
-rw-r--r--src/mbgl/style/layers/line_layer_impl.cpp35
-rw-r--r--src/mbgl/style/layers/line_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/line_layer_properties.hpp11
-rw-r--r--src/mbgl/style/layers/raster_layer.cpp28
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.cpp3
-rw-r--r--src/mbgl/style/layers/raster_layer_impl.hpp2
-rw-r--r--src/mbgl/style/layers/raster_layer_properties.hpp1
-rw-r--r--src/mbgl/style/layers/symbol_layer.cpp200
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.cpp105
-rw-r--r--src/mbgl/style/layers/symbol_layer_impl.hpp50
-rw-r--r--src/mbgl/style/layers/symbol_layer_properties.hpp29
-rw-r--r--src/mbgl/style/layout_property.hpp24
-rw-r--r--src/mbgl/style/paint_property.hpp97
-rw-r--r--src/mbgl/style/paint_property_binder.hpp287
-rw-r--r--src/mbgl/style/parser.cpp12
-rw-r--r--src/mbgl/style/possibly_evaluated_property_value.hpp67
-rw-r--r--src/mbgl/style/property_evaluator.hpp2
-rw-r--r--src/mbgl/style/source_impl.cpp6
-rw-r--r--src/mbgl/style/source_observer.hpp2
-rw-r--r--src/mbgl/style/sources/geojson_source_impl.cpp4
-rw-r--r--src/mbgl/style/style.cpp15
-rw-r--r--src/mbgl/style/style.hpp1
-rw-r--r--src/mbgl/style/tile_source_impl.hpp2
-rw-r--r--src/mbgl/text/glyph.hpp43
-rw-r--r--src/mbgl/text/glyph_atlas.cpp79
-rw-r--r--src/mbgl/text/glyph_atlas.hpp31
-rw-r--r--src/mbgl/text/glyph_pbf.cpp46
-rw-r--r--src/mbgl/text/glyph_set.cpp54
-rw-r--r--src/mbgl/text/glyph_set.hpp9
-rw-r--r--src/mbgl/text/quads.cpp27
-rw-r--r--src/mbgl/text/quads.hpp8
-rw-r--r--src/mbgl/text/shaping.cpp12
-rw-r--r--src/mbgl/text/shaping.hpp40
-rw-r--r--src/mbgl/tile/geojson_tile.cpp6
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile_data.cpp2
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp27
-rw-r--r--src/mbgl/tile/raster_tile.cpp4
-rw-r--r--src/mbgl/tile/raster_tile_worker.cpp2
-rw-r--r--src/mbgl/tile/tile_id_hash.hpp6
-rw-r--r--src/mbgl/tile/vector_tile.cpp70
-rw-r--r--src/mbgl/util/chrono.cpp2
-rw-r--r--src/mbgl/util/http_header.cpp4
-rw-r--r--src/mbgl/util/http_header.hpp2
-rw-r--r--src/mbgl/util/http_timeout.cpp4
-rw-r--r--src/mbgl/util/i18n.cpp254
-rw-r--r--src/mbgl/util/i18n.hpp50
-rw-r--r--src/mbgl/util/ignore.hpp3
-rw-r--r--src/mbgl/util/indexed_tuple.hpp13
-rw-r--r--src/mbgl/util/interpolate.cpp19
-rw-r--r--src/mbgl/util/interpolate.hpp9
-rw-r--r--src/mbgl/util/thread.hpp45
-rw-r--r--src/mbgl/util/type_list.hpp40
-rw-r--r--src/mbgl/util/url.cpp6
-rw-r--r--src/mbgl/util/version.cpp9
-rw-r--r--src/mbgl/util/version.hpp9
-rw-r--r--src/mbgl/util/version_info.cpp14
-rw-r--r--test/api/annotations.test.cpp20
-rw-r--r--test/api/api_misuse.test.cpp4
-rw-r--r--test/api/custom_layer.test.cpp2
-rw-r--r--test/api/query.test.cpp2
-rw-r--r--test/api/render_missing.test.cpp2
-rw-r--r--test/api/repeated_render.test.cpp2
-rw-r--r--test/fixtures/annotations/result-spriteatlas.pngbin1124 -> 0 bytes
-rw-r--r--test/fixtures/map/no_vao/expected.pngbin0 -> 9832 bytes
-rw-r--r--test/fixtures/sprite_atlas/basic/expected.pngbin0 -> 694 bytes
-rw-r--r--test/fixtures/sprite_atlas/size/expected.png (renamed from test/fixtures/annotations/result-spriteatlassize.png)bin1118 -> 1118 bytes
-rw-r--r--test/fixtures/sprite_atlas/updates_after/expected.png (renamed from test/fixtures/annotations/result-spriteatlas-updated.png)bin135 -> 135 bytes
-rw-r--r--test/fixtures/sprite_atlas/updates_before/expected.png (renamed from test/fixtures/annotations/result-spriteatlas-empty.png)bin110 -> 110 bytes
-rw-r--r--test/gl/bucket.test.cpp19
-rw-r--r--test/gl/object.test.cpp4
-rw-r--r--test/map/map.test.cpp109
-rw-r--r--test/map/transform.test.cpp6
-rw-r--r--test/math/wrap.test.cpp2
-rw-r--r--test/sprite/sprite_atlas.test.cpp57
-rw-r--r--test/src/mbgl/test/conversion_stubs.hpp2
-rw-r--r--test/src/mbgl/test/getrss.cpp102
-rw-r--r--test/src/mbgl/test/getrss.hpp45
-rw-r--r--test/src/mbgl/test/stub_geometry_tile_feature.hpp34
-rw-r--r--test/src/mbgl/test/stub_layer_observer.hpp5
-rw-r--r--test/src/mbgl/test/util.hpp2
-rw-r--r--test/storage/default_file_source.test.cpp46
-rw-r--r--test/storage/local_file_source.test.cpp8
-rw-r--r--test/storage/offline_database.test.cpp4
-rw-r--r--test/storage/online_file_source.test.cpp14
-rwxr-xr-xtest/storage/server.js35
-rw-r--r--test/storage/sqlite.test.cpp27
-rw-r--r--test/style/conversion/function.test.cpp2
-rw-r--r--test/style/conversion/geojson_options.test.cpp22
-rw-r--r--test/style/conversion/layer.test.cpp46
-rw-r--r--test/style/conversion/stringify.test.cpp38
-rw-r--r--test/style/function/camera_function.test.cpp (renamed from test/style/functions.test.cpp)14
-rw-r--r--test/style/function/source_function.test.cpp94
-rw-r--r--test/style/paint_property.test.cpp76
-rw-r--r--test/style/source.test.cpp8
-rw-r--r--test/style/style.test.cpp2
-rw-r--r--test/style/style_layer.test.cpp124
-rw-r--r--test/text/glyph_atlas.test.cpp37
-rw-r--r--test/text/glyph_pbf.test.cpp8
-rw-r--r--test/text/quads.test.cpp274
-rw-r--r--test/tile/geometry_tile_data.test.cpp46
-rw-r--r--test/tile/raster_tile.test.cpp15
-rw-r--r--test/tile/vector_tile.test.cpp8
-rw-r--r--test/util/http_timeout.test.cpp15
-rw-r--r--test/util/image.test.cpp29
-rw-r--r--test/util/mapbox.test.cpp3
-rw-r--r--test/util/memory.test.cpp54
-rw-r--r--test/util/merge_lines.test.cpp136
-rw-r--r--test/util/offscreen_texture.test.cpp88
-rw-r--r--test/util/thread.test.cpp78
-rw-r--r--test/util/url.test.cpp20
1170 files changed, 43875 insertions, 24158 deletions
diff --git a/.gitignore b/.gitignore
index 873b80fae8..653ff30c45 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
.DS_Store
+.transifexrc
*.pyc
*.gcno
*.gcda
diff --git a/.gitmodules b/.gitmodules
index 9a9f6c1ed1..72cbe56da7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,11 +1,6 @@
-[submodule ".mason"]
- path = .mason
- url = https://github.com/mapbox/mason.git
-
[submodule "platform/ios/vendor/SMCalloutView"]
path = platform/ios/vendor/SMCalloutView
url = https://github.com/nfarina/calloutview.git
-
[submodule "platform/ios/uitest/KIF"]
path = platform/ios/uitest/KIF
url = https://github.com/kif-framework/KIF.git
@@ -14,4 +9,4 @@
url = https://github.com/AliSoftware/OHHTTPStubs.git
[submodule "mapbox-gl-js"]
path = mapbox-gl-js
- url = git://github.com/mapbox/mapbox-gl-js.git
+ url = https://github.com/mapbox/mapbox-gl-js.git
diff --git a/.mason b/.mason
deleted file mode 160000
-Subproject a17d47e8158824449bc93b894639c78b4d33cb5
diff --git a/.travis.yml b/.travis.yml
index f29db208e6..3b13902776 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,6 @@ addons:
- &common_packages [ 'libllvm3.8v4', 'cmake', 'cmake-data' ]
- &clang38_packages [ 'clang-3.8', 'libstdc++-5-dev', 'libstdc++6' ]
- &gcc5_packages [ 'gcc-5', 'g++-5' ]
- - &egl_packages [ 'libgles2-mesa-dev', 'libgbm-dev' ]
- &glfw_packages [ 'libxrandr-dev', 'libxcursor-dev', 'libxinerama-dev' ]
addons_shortcuts:
@@ -20,7 +19,6 @@ addons_shortcuts:
packages:
- *common_packages
- *clang38_packages
- - *egl_packages
- *glfw_packages
addons_gcc5: &gcc5
apt:
@@ -28,7 +26,6 @@ addons_shortcuts:
packages:
- *common_packages
- *gcc5_packages
- - *egl_packages
- *glfw_packages
addons_qt4: &qt4
apt:
@@ -36,14 +33,14 @@ addons_shortcuts:
packages:
- *common_packages
- *gcc5_packages
- - [ 'libjemalloc-dev', 'mesa-utils', 'qt4-default' ]
+ - [ 'libjemalloc-dev', 'mesa-utils', 'qt4-default', 'libqt4-sql-mysql' ]
addons_qt5: &qt5
apt:
sources: *common_sources
packages:
- *common_packages
- *gcc5_packages
- - [ 'mesa-utils', 'libc6-dbg', 'qt5-default', 'libqt5opengl5-dev', 'qtdeclarative5-dev', 'qtpositioning5-dev', 'qtlocation5-dev' ]
+ - [ 'mesa-utils', 'libc6-dbg', 'qt5-default', 'libqt5opengl5-dev', 'qtdeclarative5-dev', 'qtpositioning5-dev', 'qtlocation5-dev', 'libqt5sql5-sqlite' ]
env:
global:
@@ -93,15 +90,19 @@ matrix:
env: BUILDTYPE=Debug _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1
addons: *clang38
before_script:
+ - mapbox_install_logbt
- mapbox_start_xvfb
+ - mapbox_export_mesa_library_path
script:
- nvm install 4
- nvm use 4
- make node
- - make test-node
+ - ./logbt -- $(scripts/mason.sh PREFIX apitrace VERSION 6a30de1)/bin/apitrace trace --api=egl -v make test-node
after_script:
- ccache --show-stats
- ./platform/node/scripts/after_script.sh ${TRAVIS_JOB_NUMBER}
+ after_failure:
+ - aws s3 cp . s3://mapbox/mapbox-gl-native/render-tests/$TRAVIS_JOB_NUMBER --recursive --exclude "*" --include "*.trace"
# EGL - Node - Clang 3.8 - Release
- os: linux
@@ -112,19 +113,25 @@ matrix:
env: BUILDTYPE=Release _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1
addons: *clang38
before_script:
+ # fglrx causes the GLX extension to be unavailable
+ - sudo apt-get purge -qq fglrx
- export PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
- export PUBLISH=$([[ "${TRAVIS_TAG:-}" == "node-v${PACKAGE_JSON_VERSION}" ]] && echo true)
+ - mapbox_install_logbt
- mapbox_start_xvfb
+ - mapbox_export_mesa_library_path
script:
- nvm install 4
- nvm use 4
- make node
- - make test-node
+ - ./logbt -- $(scripts/mason.sh PREFIX apitrace VERSION 6a30de1)/bin/apitrace trace --api=egl -v make test-node
after_script:
- ccache --show-stats
- ./platform/node/scripts/after_script.sh ${TRAVIS_JOB_NUMBER}
after_success:
- ./platform/node/scripts/after_success.sh
+ after_failure:
+ - aws s3 cp . s3://mapbox/mapbox-gl-native/render-tests/$TRAVIS_JOB_NUMBER --recursive --exclude "*" --include "*.trace"
# EGL - GCC 5 - Debug (Coverage)
- os: linux
@@ -136,21 +143,11 @@ matrix:
addons: *gcc5
before_script:
- mapbox_start_xvfb
+ - mapbox_export_mesa_library_path
after_script:
- ccache --show-stats
- ./platform/linux/scripts/coveralls.sh
- # EGL - GCC 5 - Release
- - os: linux
- sudo: required
- dist: trusty
- language: cpp
- compiler: "egl-gcc5-release"
- env: BUILDTYPE=Release _CXX=g++-5 _CC=gcc-5 WITH_EGL=1
- addons: *gcc5
- before_script:
- - mapbox_start_xvfb
-
# EGL - Clang 3.8 - Debug
- os: linux
sudo: required
@@ -161,17 +158,7 @@ matrix:
addons: *clang38
before_script:
- mapbox_start_xvfb
-
- # EGL - Clang 3.8 - Release
- - os: linux
- sudo: required
- dist: trusty
- language: cpp
- compiler: "egl-clang38-release"
- env: BUILDTYPE=Release _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1
- addons: *clang38
- before_script:
- - mapbox_start_xvfb
+ - mapbox_export_mesa_library_path
# Qt 4 - GCC 5 - Release
- os: linux
@@ -186,7 +173,8 @@ matrix:
- mapbox_export_mesa_library_path
script:
- make qt-app
- - LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so make run-qt-test-Memory.*:*.Load
+ - GTEST_OUTPUT=xml LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so make run-qt-test-Memory.*:*.Load
+ - scripts/log_memory_benchmarks.sh test_detail.xml "Platform=Linux,Compiler=${_CC},Arch=$(uname -m)"
# Qt 5 - GCC 5 - Release
- os: linux
@@ -203,7 +191,8 @@ matrix:
- make qt-app
- make qt-qml-app
- make qt-test
- - scripts/valgrind.sh build/qt-linux-x86_64/Release/mbgl-test --gtest_filter=-*.Load
+ - make qt-docs
+ - scripts/valgrind.sh build/qt-linux-x86_64/Release/mbgl-test --gtest_filter=-*.Load --gtest_filter=-Memory.Vector
cache:
directories:
diff --git a/.tx/config b/.tx/config
new file mode 100644
index 0000000000..52720dc3ee
--- /dev/null
+++ b/.tx/config
@@ -0,0 +1,25 @@
+[main]
+host = https://www.transifex.com
+lang_map = pt_BR: pt-BR, pt_PT: pt-PT, zh_CN: zh-Hans, zh_TW: zh-Hant
+type = STRINGS
+minimum_perc = 80
+
+[mapbox-gl-native.foundationstrings-darwin]
+source_file = platform/darwin/resources/Base.lproj/Foundation.strings
+source_lang = en
+file_filter = platform/darwin/resources/<lang>.lproj/Foundation.strings
+
+[mapbox-gl-native.localizablestrings-ios]
+source_file = platform/ios/resources/Base.lproj/Localizable.strings
+source_lang = en
+file_filter = platform/ios/resources/<lang>.lproj/Localizable.strings
+
+[mapbox-gl-native.localizablestrings-macos]
+source_file = platform/macos/sdk/Base.lproj/Localizable.strings
+source_lang = en
+file_filter = platform/macos/sdk/<lang>.lproj/Localizable.strings
+
+[mapbox-gl-native.rootstrings-ios]
+source_file = platform/ios/framework/Settings.bundle/Base.lproj/Root.strings
+source_lang = en
+file_filter = platform/ios/framework/Settings.bundle/<lang>.lproj/Root.strings
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 92b0715b5e..90f5bf7e1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,13 +3,12 @@ project(mbgl LANGUAGES CXX C)
set(CMAKE_CXX_STANDARD 14)
include(cmake/mbgl.cmake)
-include(.mason/mason.cmake)
+include(cmake/mason.cmake)
option(WITH_CXX11ABI "Use cxx11abi mason packages" OFF)
option(WITH_COVERAGE "Enable coverage reports" OFF)
option(WITH_OSMESA "Use OSMesa headless backend" OFF)
option(WITH_EGL "Use EGL backend" OFF)
-option(IS_CI_BUILD "Continuous integration build" OFF)
if(WITH_CXX11ABI)
set(MASON_CXXABI_SUFFIX -cxx11abi)
@@ -19,28 +18,34 @@ if(WITH_OSMESA AND WITH_EGL)
message(FATAL_ERROR "WITH_OSMESA and WITH_EGL are mutually exclusive.")
endif()
-if(WITH_OSMESA)
- # Default mesa mason binary is OSMesa.
- set(MASON_MESA_SUFFIX "")
-elseif(WITH_EGL)
+if(WITH_EGL)
add_definitions(-DMBGL_USE_GLES2=1)
- set(MASON_MESA_SUFFIX "-egl")
-else()
- set(MASON_MESA_SUFFIX "-glx")
endif()
-if(IS_CI_BUILD)
+if($ENV{CI})
add_compile_options(-DCI_BUILD=1)
endif()
+if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD)
+ exec_program(
+ "git"
+ ${CMAKE_SOURCE_DIR}
+ ARGS "rev-parse --short=8 HEAD"
+ OUTPUT_VARIABLE MBGL_VERSION_REV )
+else()
+ set(MBGL_VERSION_REV 00000000)
+endif()
+
+set_source_files_properties(src/mbgl/util/version.cpp PROPERTIES COMPILE_DEFINITIONS MBGL_VERSION_REV="${MBGL_VERSION_REV}")
+
mason_use(geometry VERSION 0.9.0 HEADER_ONLY)
mason_use(variant VERSION 1.1.4 HEADER_ONLY)
-mason_use(unique_resource VERSION dev HEADER_ONLY)
+mason_use(unique_resource VERSION cba309e HEADER_ONLY)
mason_use(rapidjson VERSION 1.1.0 HEADER_ONLY)
mason_use(boost VERSION 1.62.0 HEADER_ONLY)
-mason_use(geojsonvt VERSION 6.1.3 HEADER_ONLY)
-mason_use(supercluster VERSION 0.2.0 HEADER_ONLY)
-mason_use(kdbush VERSION 0.1.1 HEADER_ONLY)
+mason_use(geojsonvt VERSION 6.2.0 HEADER_ONLY)
+mason_use(supercluster VERSION 0.2.0-1 HEADER_ONLY)
+mason_use(kdbush VERSION 0.1.1-1 HEADER_ONLY)
mason_use(earcut VERSION 0.12.1 HEADER_ONLY)
mason_use(protozero VERSION 1.4.2 HEADER_ONLY)
mason_use(pixelmatch VERSION 0.10.0 HEADER_ONLY)
@@ -74,7 +79,6 @@ endif()
include(platform/${MBGL_PLATFORM}/config.cmake)
include(cmake/core-files.cmake)
-include(cmake/shaders.cmake)
include(cmake/core.cmake)
if(COMMAND mbgl_platform_test)
diff --git a/Makefile b/Makefile
index c4e123d645..0da2dc159e 100644
--- a/Makefile
+++ b/Makefile
@@ -9,12 +9,12 @@ endif
ifeq ($(shell uname -s), Darwin)
HOST_PLATFORM = macos
HOST_PLATFORM_VERSION = $(shell uname -m)
- NINJA ?= platform/macos/ninja
+ export NINJA = platform/macos/ninja
export JOBS ?= $(shell sysctl -n hw.ncpu)
else ifeq ($(shell uname -s), Linux)
HOST_PLATFORM = linux
HOST_PLATFORM_VERSION = $(shell uname -m)
- NINJA ?= platform/linux/ninja
+ export NINJA = platform/linux/ninja
export JOBS ?= $(shell grep --count processor /proc/cpuinfo)
else
$(error Cannot determine host platform)
@@ -32,6 +32,10 @@ else
BUILD_PLATFORM_VERSION = $(MASON_PLATFORM_VERSION)
endif
+ifeq ($(MASON_PLATFORM),macos)
+ MASON_PLATFORM=osx
+endif
+
ifeq ($(V), 1)
export XCPRETTY
NINJA_ARGS ?= -v
@@ -43,20 +47,7 @@ endif
.PHONY: default
default: test
-ifneq (,$(wildcard .git/.))
-.mason/mason:
- git submodule update --init
-else
-.mason/mason: ;
-endif
-
-.NOTPARALLEL: node_modules
-node_modules: package.json
- npm install --ignore-scripts # Install dependencies but don't run our own install script.
-
-BUILD_DEPS += .mason/mason
BUILD_DEPS += Makefile
-BUILD_DEPS += node_modules
BUILD_DEPS += CMakeLists.txt
#### macOS targets ##############################################################
@@ -190,18 +181,12 @@ $(MACOS_COMPDB_PATH)/Makefile:
compdb: $(BUILD_DEPS) $(TEST_DEPS) $(MACOS_COMPDB_PATH)/Makefile
@$(MAKE) -C $(MACOS_COMPDB_PATH) cmake_check_build_system
-.PHONY: clang-tools
-clang-tools: compdb
- if test -z $(CLANG_TIDY); then .mason/mason install clang-tidy 3.9.1; fi
- if test -z $(CLANG_FORMAT); then .mason/mason install clang-format 3.9.1; fi
- $(MAKE) -C $(MACOS_COMPDB_PATH) mbgl-headers
-
.PHONY: tidy
-tidy: clang-tools
+tidy: compdb
scripts/clang-tools.sh $(MACOS_COMPDB_PATH)
.PHONY: check
-check: clang-tools
+check: compdb
scripts/clang-tools.sh $(MACOS_COMPDB_PATH) --diff
endif
@@ -226,7 +211,9 @@ $(IOS_PROJ_PATH): $(IOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings $(BUILD_DEP
mkdir -p $(IOS_OUTPUT_PATH)
(cd $(IOS_OUTPUT_PATH) && cmake -G Xcode ../.. \
-DCMAKE_TOOLCHAIN_FILE=../../platform/ios/toolchain.cmake \
- -DMBGL_PLATFORM=ios)
+ -DMBGL_PLATFORM=ios \
+ -DMASON_PLATFORM=ios \
+ -DMASON_PLATFORM_VERSION=8.0)
$(IOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings: platform/ios/WorkspaceSettings.xcsettings
mkdir -p "$(IOS_USER_DATA_PATH)"
@@ -307,7 +294,6 @@ $(LINUX_BUILD): $(BUILD_DEPS)
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DWITH_CXX11ABI=$(shell scripts/check-cxx11abi.sh) \
-DWITH_COVERAGE=${WITH_COVERAGE} \
- -DIS_CI_BUILD=${CI} \
-DWITH_OSMESA=${WITH_OSMESA} \
-DWITH_EGL=${WITH_EGL})
@@ -362,18 +348,12 @@ node: $(LINUX_BUILD)
compdb: $(LINUX_BUILD)
# Ninja generator already outputs the file at the right location
-.PHONY: clang-tools
-clang-tools: compdb
- if test -z $(CLANG_TIDY); then .mason/mason install clang-tidy 3.9.1; fi
- if test -z $(CLANG_FORMAT); then .mason/mason install clang-format 3.9.1; fi
- $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C $(LINUX_OUTPUT_PATH) mbgl-headers
-
.PHONY: tidy
-tidy: clang-tools
+tidy: compdb
scripts/clang-tools.sh $(LINUX_OUTPUT_PATH)
.PHONY: check
-check: clang-tools
+check: compdb
scripts/clang-tools.sh $(LINUX_OUTPUT_PATH) --diff
endif
@@ -399,14 +379,13 @@ $(QT_BUILD): $(BUILD_DEPS)
-DCMAKE_BUILD_TYPE=$(BUILDTYPE) \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DMBGL_PLATFORM=qt \
- -DMASON_PLATFORM=$(BUILD_PLATFORM) \
- -DMASON_PLATFORM_VERSION=$(BUILD_PLATFORM_VERSION) \
+ -DMASON_PLATFORM=$(MASON_PLATFORM) \
+ -DMASON_PLATFORM_VERSION=$(MASON_PLATFORM_VERSION) \
-DWITH_QT_DECODERS=${WITH_QT_DECODERS} \
-DWITH_QT_I18N=${WITH_QT_I18N} \
-DWITH_QT_4=${WITH_QT_4} \
-DWITH_CXX11ABI=$(shell scripts/check-cxx11abi.sh) \
- -DWITH_COVERAGE=${WITH_COVERAGE} \
- -DIS_CI_BUILD=${CI})
+ -DWITH_COVERAGE=${WITH_COVERAGE})
ifeq ($(HOST_PLATFORM), macos)
@@ -415,14 +394,13 @@ $(MACOS_QT_PROJ_PATH): $(BUILD_DEPS)
mkdir -p $(QT_ROOT_PATH)/xcode
(cd $(QT_ROOT_PATH)/xcode && cmake -G Xcode ../../.. \
-DMBGL_PLATFORM=qt \
- -DMASON_PLATFORM=$(BUILD_PLATFORM) \
- -DMASON_PLATFORM_VERSION=$(BUILD_PLATFORM_VERSION) \
+ -DMASON_PLATFORM=$(MASON_PLATFORM) \
+ -DMASON_PLATFORM_VERSION=$(MASON_PLATFORM_VERSION) \
-DWITH_QT_DECODERS=${WITH_QT_DECODERS} \
-DWITH_QT_I18N=${WITH_QT_I18N} \
-DWITH_QT_4=${WITH_QT_4} \
-DWITH_CXX11ABI=$(shell scripts/check-cxx11abi.sh) \
- -DWITH_COVERAGE=${WITH_COVERAGE} \
- -DIS_CI_BUILD=${CI})
+ -DWITH_COVERAGE=${WITH_COVERAGE})
@# Create Xcode schemes so that we can use xcodebuild from the command line. CMake doesn't
@# create these automatically.
@@ -471,7 +449,7 @@ run-qt-test: run-qt-test-*
.PHONY: qt-docs
qt-docs:
- qdoc $(shell pwd)/platform/qt/config.qdocconf --outputdir $(shell pwd)/$(QT_OUTPUT_PATH)/docs
+ qdoc $(shell pwd)/platform/qt/config.qdocconf -outputdir $(shell pwd)/$(QT_OUTPUT_PATH)/docs
#### Node targets ##############################################################
@@ -482,13 +460,41 @@ test-node: node
#### Android targets ###########################################################
-MBGL_ANDROID_ENV = platform/android/scripts/toolchain.sh
-MBGL_ANDROID_ABIS = arm-v5 arm-v7 arm-v8 x86 x86-64 mips
+MBGL_ANDROID_ABIS = arm-v5;armeabi;9
+MBGL_ANDROID_ABIS += arm-v7;armeabi-v7a;9
+MBGL_ANDROID_ABIS += arm-v8;arm64-v8a;21
+MBGL_ANDROID_ABIS += x86;x86;9
+MBGL_ANDROID_ABIS += x86-64;x86_64;21
+MBGL_ANDROID_ABIS += mips;mips;9
+
+MBGL_ANDROID_BUILD_DIR = build/android-$1-$3/$(BUILDTYPE)
MBGL_ANDROID_LOCAL_WORK_DIR = /data/local/tmp/core-tests
MBGL_ANDROID_LIBDIR = lib$(if $(filter arm-v8 x86-64,$1),64)
MBGL_ANDROID_DALVIKVM = dalvikvm$(if $(filter arm-v8 x86-64,$1),64,32)
MBGL_ANDROID_APK_SUFFIX = $(if $(filter Release,$(BUILDTYPE)),release-unsigned,debug)
-MBGL_ANDROID_CORE_TEST_DIR = build/android-$1/$(BUILDTYPE)/core-tests
+MBGL_ANDROID_CORE_TEST_DIR = $(MBGL_ANDROID_BUILD_DIR)/core-tests
+
+.PHONY: android-help
+android-help:
+ @echo
+ @echo "Available Android architecture targets:"
+ @echo
+ @echo " make android-arm-v5-9"
+ @echo " (android-arm-v5)"
+ @echo " make android-arm-v7-9"
+ @echo " (android, android-arm-v7)"
+ @echo " make android-arm-v8-21"
+ @echo " (android-arm-v8)"
+ @echo " make android-mips-9"
+ @echo " (android-mips)"
+ @echo " make android-mips-64-21"
+ @echo " (android-mips-64)"
+ @echo " make android-x86-9"
+ @echo " (android-x86)"
+ @echo " make android-x86-64-21"
+ @echo " (android-x86-64)"
+ @echo " make apackage"
+ @echo
.PHONY: android-style-code
android-style-code:
@@ -496,27 +502,39 @@ android-style-code:
style-code: android-style-code
define ANDROID_RULES
-
-build/android-$1/$(BUILDTYPE): $(BUILD_DEPS)
- mkdir -p build/android-$1/$(BUILDTYPE)
-
-build/android-$1/$(BUILDTYPE)/toolchain.cmake: platform/android/scripts/toolchain.sh build/android-$1/$(BUILDTYPE)
- $(MBGL_ANDROID_ENV) $1 > build/android-$1/$(BUILDTYPE)/toolchain.cmake
-
-build/android-$1/$(BUILDTYPE)/Makefile: build/android-$1/$(BUILDTYPE)/toolchain.cmake platform/android/config.cmake
- cd build/android-$1/$(BUILDTYPE) && cmake ../../.. -G Ninja \
- -DCMAKE_TOOLCHAIN_FILE=build/android-$1/$(BUILDTYPE)/toolchain.cmake \
- -DCMAKE_BUILD_TYPE=$(BUILDTYPE) \
- -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
- -DMBGL_PLATFORM=android
+# $1 = arm-v7 (short arch)
+# $2 = armeabi-v7a (internal arch)
+# $3 = 9 (platform version)
+
+$(MBGL_ANDROID_BUILD_DIR)/env.sh: $(BUILD_DEPS) platform/android/scripts/ndk.sh
+ @mkdir -p $(MBGL_ANDROID_BUILD_DIR)
+ platform/android/scripts/ndk.sh $1 $2 $3 > $(MBGL_ANDROID_BUILD_DIR)/env.sh.tmp && \
+ mv $(MBGL_ANDROID_BUILD_DIR)/env.sh.tmp $(MBGL_ANDROID_BUILD_DIR)/env.sh
+
+$(MBGL_ANDROID_BUILD_DIR)/build.ninja: $(MBGL_ANDROID_BUILD_DIR)/env.sh platform/android/config.cmake
+ # Invoke CMake twice to fix issues from double inclusion of toolchain.cmake on the first run.
+ . $(MBGL_ANDROID_BUILD_DIR)/env.sh && \
+ ([ -f $(MBGL_ANDROID_BUILD_DIR)/build.ninja ] || $$$${CMAKE} \
+ -H. \
+ -B"$(MBGL_ANDROID_BUILD_DIR)" \
+ -G"$$$${CMAKE_GENERATOR}" \
+ $$$${CMAKE_ARGS} \
+ -DCMAKE_BUILD_TYPE=$(BUILDTYPE) \
+ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
+ -DMBGL_PLATFORM=android \
+ -DMASON_PLATFORM=android \
+ -DMASON_PLATFORM_VERSION=$1-$3) && \
+ $$$${CMAKE} \
+ -H. \
+ -B"$(MBGL_ANDROID_BUILD_DIR)"
.PHONY: android-test-lib-$1
-android-test-lib-$1: build/android-$1/$(BUILDTYPE)/Makefile
- $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C build/android-$1/$(BUILDTYPE) mbgl-test
+android-test-lib-$1: $(MBGL_ANDROID_BUILD_DIR)/build.ninja
+ . $(MBGL_ANDROID_BUILD_DIR)/env.sh && $$$${CMAKE} --build $(MBGL_ANDROID_BUILD_DIR) -- $(NINJA_ARGS) -j$(JOBS) mbgl-test
.PHONY: android-lib-$1
-android-lib-$1: build/android-$1/$(BUILDTYPE)/Makefile
- $(NINJA) $(NINJA_ARGS) -j$(JOBS) -C build/android-$1/$(BUILDTYPE) mapbox-gl example-custom-layer
+android-lib-$1: $(MBGL_ANDROID_BUILD_DIR)/build.ninja
+ . $(MBGL_ANDROID_BUILD_DIR)/env.sh && $$$${CMAKE} --build $(MBGL_ANDROID_BUILD_DIR) -- $(NINJA_ARGS) -j$(JOBS) mapbox-gl example-custom-layer
.PHONY: android-$1
android-$1: android-lib-$1
@@ -548,8 +566,8 @@ run-android-core-test-$1-%: android-core-test-$1
# Push all needed files to the device
adb push $(MBGL_ANDROID_CORE_TEST_DIR)/test.jar $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
adb push test/fixtures $(MBGL_ANDROID_LOCAL_WORK_DIR)/test > /dev/null 2>&1
- adb push build/android-$1/$(BUILDTYPE)/stripped/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
- adb push build/android-$1/$(BUILDTYPE)/stripped/libmbgl-test.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
+ adb push $(MBGL_ANDROID_BUILD_DIR)/stripped/libmapbox-gl.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
+ adb push $(MBGL_ANDROID_BUILD_DIR)/stripped/libmbgl-test.so $(MBGL_ANDROID_LOCAL_WORK_DIR) > /dev/null 2>&1
# Kick off the tests
adb shell "export LD_LIBRARY_PATH=/system/$(MBGL_ANDROID_LIBDIR):$(MBGL_ANDROID_LOCAL_WORK_DIR) && cd $(MBGL_ANDROID_LOCAL_WORK_DIR) && $(MBGL_ANDROID_DALVIKVM) -cp $(MBGL_ANDROID_LOCAL_WORK_DIR)/test.jar Main --gtest_filter=$$*"
@@ -565,12 +583,18 @@ run-android-core-test-$1: run-android-core-test-$1-*
.PHONY: run-android-$1
run-android-$1: android-$1
+ adb uninstall com.mapbox.mapboxsdk.testapp > /dev/null
cd platform/android && ./gradlew :MapboxGLAndroidSDKTestApp:install$(BUILDTYPE) && adb shell am start -n com.mapbox.mapboxsdk.testapp/.activity.FeatureOverviewActivity
apackage: android-lib-$1
endef
-$(foreach abi,$(MBGL_ANDROID_ABIS),$(eval $(call ANDROID_RULES,$(abi))))
+# Explodes the arguments into individual variables
+define ANDROID_RULES_INVOKER
+$(call ANDROID_RULES,$(word 1,$1),$(word 2,$1),$(word 3,$1))
+endef
+
+$(foreach abi,$(MBGL_ANDROID_ABIS),$(eval $(call ANDROID_RULES_INVOKER,$(subst ;, ,$(abi)))))
.PHONY: android
android: android-arm-v7
@@ -595,10 +619,12 @@ android-ui-test:
.PHONY: run-android-ui-test
run-android-ui-test:
+ adb uninstall com.mapbox.mapboxsdk.testapp > /dev/null
cd platform/android && ./gradlew :MapboxGLAndroidSDKTestApp:connectedAndroidTest -i
run-android-ui-test-%:
- cd platform/android && ./gradlew :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="$*"
+ adb uninstall com.mapbox.mapboxsdk.testapp > /dev/null
+ cd platform/android && ./gradlew :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="$*"
.PHONY: run-android-ui-test-aws
run-android-ui-test-aws:
@@ -618,17 +644,26 @@ test-code-android:
.PHONY: android-ndk-stack
android-ndk-stack:
- adb logcat | ndk-stack -sym build/android-arm-v7/Debug
+ adb logcat | ndk-stack -sym build/android-arm-v7-9/Debug
.PHONY: android-checkstyle
android-checkstyle:
cd platform/android && ./gradlew checkstyle
+.PHONY: android-javadoc
+android-javadoc:
+ cd platform/android && ./gradlew :MapboxGLAndroidSDK:javadocrelease
+
#### Miscellaneous targets #####################################################
.PHONY: style-code
style-code:
node scripts/generate-style-code.js
+ node scripts/generate-shaders.js
+
+.PHONY: codestyle
+codestyle:
+ scripts/codestyle.sh
.PHONY: clean
clean:
diff --git a/benchmark/api/query.benchmark.cpp b/benchmark/api/query.benchmark.cpp
index ba696876cd..f7474dd2ee 100644
--- a/benchmark/api/query.benchmark.cpp
+++ b/benchmark/api/query.benchmark.cpp
@@ -37,7 +37,7 @@ public:
OffscreenView view{ backend.getContext(), { 1000, 1000 } };
DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." };
ThreadPool threadPool{ 4 };
- Map map{ backend, view.size, 1, fileSource, threadPool, MapMode::Still };
+ Map map{ backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
ScreenBox box{{ 0, 0 }, { 1000, 1000 }};
};
diff --git a/cmake/NodeJS.cmake b/cmake/NodeJS.cmake
new file mode 100644
index 0000000000..8e0ec56982
--- /dev/null
+++ b/cmake/NodeJS.cmake
@@ -0,0 +1,600 @@
+# 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/core-files.cmake b/cmake/core-files.cmake
index 4f2375e462..2c2b04f9ed 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -70,11 +70,13 @@ set(MBGL_CORE_FILES
src/mbgl/gl/framebuffer.hpp
src/mbgl/gl/gl.cpp
src/mbgl/gl/index_buffer.hpp
+ src/mbgl/gl/normalization.hpp
src/mbgl/gl/object.cpp
src/mbgl/gl/object.hpp
src/mbgl/gl/primitives.hpp
src/mbgl/gl/program.hpp
src/mbgl/gl/renderbuffer.hpp
+ src/mbgl/gl/segment.cpp
src/mbgl/gl/segment.hpp
src/mbgl/gl/state.hpp
src/mbgl/gl/stencil_mode.cpp
@@ -102,11 +104,13 @@ set(MBGL_CORE_FILES
# map
include/mbgl/map/backend.hpp
+ include/mbgl/map/backend_scope.hpp
include/mbgl/map/camera.hpp
include/mbgl/map/map.hpp
include/mbgl/map/mode.hpp
include/mbgl/map/view.hpp
src/mbgl/map/backend.cpp
+ src/mbgl/map/backend_scope.cpp
src/mbgl/map/change.hpp
src/mbgl/map/map.cpp
src/mbgl/map/transform.cpp
@@ -179,6 +183,34 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/symbol_bucket.cpp
src/mbgl/renderer/symbol_bucket.hpp
+ # shaders
+ src/mbgl/shaders/circle.cpp
+ src/mbgl/shaders/circle.hpp
+ src/mbgl/shaders/collision_box.cpp
+ src/mbgl/shaders/collision_box.hpp
+ src/mbgl/shaders/debug.cpp
+ src/mbgl/shaders/debug.hpp
+ src/mbgl/shaders/fill.cpp
+ src/mbgl/shaders/fill.hpp
+ src/mbgl/shaders/fill_outline.cpp
+ src/mbgl/shaders/fill_outline.hpp
+ src/mbgl/shaders/fill_outline_pattern.cpp
+ src/mbgl/shaders/fill_outline_pattern.hpp
+ src/mbgl/shaders/fill_pattern.cpp
+ src/mbgl/shaders/fill_pattern.hpp
+ src/mbgl/shaders/line.cpp
+ src/mbgl/shaders/line.hpp
+ src/mbgl/shaders/line_pattern.cpp
+ src/mbgl/shaders/line_pattern.hpp
+ src/mbgl/shaders/line_sdf.cpp
+ src/mbgl/shaders/line_sdf.hpp
+ src/mbgl/shaders/raster.cpp
+ src/mbgl/shaders/raster.hpp
+ src/mbgl/shaders/symbol_icon.cpp
+ src/mbgl/shaders/symbol_icon.hpp
+ src/mbgl/shaders/symbol_sdf.cpp
+ src/mbgl/shaders/symbol_sdf.hpp
+
# sprite
include/mbgl/sprite/sprite_image.hpp
src/mbgl/sprite/sprite_atlas.cpp
@@ -205,14 +237,15 @@ set(MBGL_CORE_FILES
# style
include/mbgl/style/conversion.hpp
+ include/mbgl/style/data_driven_property_value.hpp
include/mbgl/style/filter.hpp
include/mbgl/style/filter_evaluator.hpp
- include/mbgl/style/function.hpp
include/mbgl/style/layer.hpp
include/mbgl/style/property_value.hpp
include/mbgl/style/source.hpp
include/mbgl/style/transition_options.hpp
include/mbgl/style/types.hpp
+ include/mbgl/style/undefined.hpp
src/mbgl/style/bucket_parameters.cpp
src/mbgl/style/bucket_parameters.hpp
src/mbgl/style/cascade_parameters.hpp
@@ -220,7 +253,7 @@ set(MBGL_CORE_FILES
src/mbgl/style/class_dictionary.hpp
src/mbgl/style/cross_faded_property_evaluator.cpp
src/mbgl/style/cross_faded_property_evaluator.hpp
- src/mbgl/style/function.cpp
+ src/mbgl/style/data_driven_property_evaluator.hpp
src/mbgl/style/group_by_layout.cpp
src/mbgl/style/group_by_layout.hpp
src/mbgl/style/layer.cpp
@@ -230,8 +263,10 @@ set(MBGL_CORE_FILES
src/mbgl/style/layout_property.hpp
src/mbgl/style/observer.hpp
src/mbgl/style/paint_property.hpp
+ src/mbgl/style/paint_property_binder.hpp
src/mbgl/style/parser.cpp
src/mbgl/style/parser.hpp
+ src/mbgl/style/possibly_evaluated_property_value.hpp
src/mbgl/style/property_evaluation_parameters.hpp
src/mbgl/style/property_evaluator.hpp
src/mbgl/style/property_parsing.cpp
@@ -252,6 +287,7 @@ set(MBGL_CORE_FILES
# style/conversion
include/mbgl/style/conversion/constant.hpp
+ include/mbgl/style/conversion/data_driven_property_value.hpp
include/mbgl/style/conversion/filter.hpp
include/mbgl/style/conversion/function.hpp
include/mbgl/style/conversion/geojson.hpp
@@ -262,8 +298,23 @@ set(MBGL_CORE_FILES
include/mbgl/style/conversion/property_value.hpp
include/mbgl/style/conversion/source.hpp
include/mbgl/style/conversion/tileset.hpp
+ include/mbgl/style/conversion/transition_options.hpp
src/mbgl/style/conversion/stringify.hpp
+ # style/function
+ include/mbgl/style/function/camera_function.hpp
+ include/mbgl/style/function/categorical_stops.hpp
+ include/mbgl/style/function/composite_categorical_stops.hpp
+ include/mbgl/style/function/composite_exponential_stops.hpp
+ include/mbgl/style/function/composite_function.hpp
+ include/mbgl/style/function/composite_interval_stops.hpp
+ include/mbgl/style/function/exponential_stops.hpp
+ include/mbgl/style/function/identity_stops.hpp
+ include/mbgl/style/function/interval_stops.hpp
+ include/mbgl/style/function/source_function.hpp
+ src/mbgl/style/function/categorical_stops.cpp
+ src/mbgl/style/function/identity_stops.cpp
+
# style/layers
include/mbgl/style/layers/background_layer.hpp
include/mbgl/style/layers/circle_layer.hpp
@@ -442,6 +493,7 @@ set(MBGL_CORE_FILES
src/mbgl/util/i18n.hpp
src/mbgl/util/ignore.hpp
src/mbgl/util/indexed_tuple.hpp
+ src/mbgl/util/interpolate.cpp
src/mbgl/util/interpolate.hpp
src/mbgl/util/intersection_tests.cpp
src/mbgl/util/intersection_tests.hpp
@@ -474,10 +526,12 @@ set(MBGL_CORE_FILES
src/mbgl/util/tile_cover.cpp
src/mbgl/util/tile_cover.hpp
src/mbgl/util/token.hpp
+ src/mbgl/util/type_list.hpp
src/mbgl/util/url.cpp
src/mbgl/util/url.hpp
src/mbgl/util/utf.hpp
- src/mbgl/util/version_info.cpp
+ src/mbgl/util/version.cpp
+ src/mbgl/util/version.hpp
src/mbgl/util/work_queue.cpp
src/mbgl/util/work_queue.hpp
src/mbgl/util/work_request.cpp
diff --git a/cmake/core.cmake b/cmake/core.cmake
index 8d8a942d9f..59de7708b6 100644
--- a/cmake/core.cmake
+++ b/cmake/core.cmake
@@ -1,28 +1,7 @@
-set(MBGL_VERSION_DEPS package.json)
-if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD)
- set(MBGL_VERSION_DEPS ${MBGL_VERSION_DEPS} .git/HEAD)
-endif()
-
-add_custom_command(
- OUTPUT ${MBGL_GENERATED}/include/mbgl/util/version.hpp
- DEPENDS ${MBGL_VERSION_DEPS}
- COMMAND ${NodeJS_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/build-version.js ${MBGL_GENERATED}
- VERBATIM
-)
-
-add_custom_target(mbgl-headers DEPENDS
- ${MBGL_GENERATED}/include/mbgl/util/version.hpp
- ${MBGL_SHADER_FILES}
-)
-
add_library(mbgl-core STATIC
${MBGL_CORE_FILES}
)
-add_dependencies(mbgl-core
- mbgl-headers
-)
-
target_compile_options(mbgl-core
PRIVATE -fPIC
PRIVATE -fvisibility-inlines-hidden
@@ -31,7 +10,6 @@ target_compile_options(mbgl-core
target_include_directories(mbgl-core
PUBLIC include
PUBLIC src # TODO: make private
- PRIVATE ${MBGL_GENERATED}/include
)
target_add_mason_package(mbgl-core PUBLIC geometry)
diff --git a/cmake/glfw.cmake b/cmake/glfw.cmake
index d63bdbc1cf..cdde92bbf2 100644
--- a/cmake/glfw.cmake
+++ b/cmake/glfw.cmake
@@ -25,13 +25,6 @@ target_link_libraries(mbgl-glfw
PRIVATE mbgl-core
)
-add_custom_command(
- TARGET mbgl-glfw POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy
- ${CMAKE_SOURCE_DIR}/common/ca-bundle.crt
- ${CMAKE_CURRENT_BINARY_DIR}/ca-bundle.crt
-)
-
target_add_mason_package(mbgl-glfw PRIVATE glfw)
mbgl_platform_glfw()
diff --git a/cmake/mason.cmake b/cmake/mason.cmake
new file mode 100644
index 0000000000..4e4e46b619
--- /dev/null
+++ b/cmake/mason.cmake
@@ -0,0 +1,212 @@
+# Mason CMake
+
+include(CMakeParseArguments)
+
+function(mason_detect_platform)
+ # Determine platform
+ if(NOT MASON_PLATFORM)
+ # we call uname -s manually here since
+ # CMAKE_HOST_SYSTEM_NAME will not be defined before the project() call
+ execute_process(
+ COMMAND uname -s
+ OUTPUT_VARIABLE UNAME
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ if (UNAME STREQUAL "Darwin")
+ set(MASON_PLATFORM "osx" PARENT_SCOPE)
+ else()
+ set(MASON_PLATFORM "linux" PARENT_SCOPE)
+ endif()
+ endif()
+
+ # Determine platform version string
+ if(NOT MASON_PLATFORM_VERSION)
+ execute_process(
+ COMMAND uname -m
+ OUTPUT_VARIABLE MASON_PLATFORM_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(MASON_PLATFORM_VERSION "${MASON_PLATFORM_VERSION}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(mason_use _PACKAGE)
+ if(NOT _PACKAGE)
+ message(FATAL_ERROR "[Mason] No package name given")
+ endif()
+
+ cmake_parse_arguments("" "HEADER_ONLY" "VERSION" "" ${ARGN})
+
+ if(_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "[Mason] mason_use() called with unrecognized arguments: ${_UNPARSED_ARGUMENTS}")
+ endif()
+
+ if(NOT _VERSION)
+ message(FATAL_ERROR "[Mason] Specifying a version is required")
+ endif()
+
+ if(MASON_PACKAGE_${_PACKAGE}_INVOCATION STREQUAL "${MASON_INVOCATION}")
+ # Check that the previous invocation of mason_use didn't select another version of this package
+ if(NOT MASON_PACKAGE_${_PACKAGE}_VERSION STREQUAL ${_VERSION})
+ message(FATAL_ERROR "[Mason] Already using ${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_VERSION}. Cannot select version ${_VERSION}.")
+ endif()
+ else()
+ if(_HEADER_ONLY)
+ set(_PLATFORM_ID "headers")
+ else()
+ set(_PLATFORM_ID "${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}")
+ endif()
+
+ set(_SLUG "${_PLATFORM_ID}/${_PACKAGE}/${_VERSION}")
+ set(_INSTALL_PATH "${MASON_PACKAGE_DIR}/${_SLUG}")
+ file(RELATIVE_PATH _INSTALL_PATH_RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${_INSTALL_PATH}")
+
+ if(NOT EXISTS "${_INSTALL_PATH}")
+ set(_CACHE_PATH "${MASON_PACKAGE_DIR}/.binaries/${_SLUG}.tar.gz")
+ if (NOT EXISTS "${_CACHE_PATH}")
+ # Download the package
+ set(_URL "${MASON_REPOSITORY}/${_SLUG}.tar.gz")
+ message("[Mason] Downloading package ${_URL}...")
+
+ set(_FAILED)
+ set(_ERROR)
+ # Note: some CMake versions are compiled without SSL support
+ get_filename_component(_CACHE_DIR "${_CACHE_PATH}" DIRECTORY)
+ file(MAKE_DIRECTORY "${_CACHE_DIR}")
+ execute_process(
+ COMMAND curl --retry 3 -s -f -S -L "${_URL}" -o "${_CACHE_PATH}.tmp"
+ RESULT_VARIABLE _FAILED
+ ERROR_VARIABLE _ERROR)
+ if(_FAILED)
+ message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_ERROR}")
+ else()
+ # We downloaded to a temporary file to prevent half-finished downloads
+ file(RENAME "${_CACHE_PATH}.tmp" "${_CACHE_PATH}")
+ endif()
+ endif()
+
+ # Unpack the package
+ message("[Mason] Unpacking package to ${_INSTALL_PATH_RELATIVE}...")
+ file(MAKE_DIRECTORY "${_INSTALL_PATH}")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E tar xzf "${_CACHE_PATH}"
+ WORKING_DIRECTORY "${_INSTALL_PATH}")
+ endif()
+
+ # Error out if there is no config file.
+ if(NOT EXISTS "${_INSTALL_PATH}/mason.ini")
+ message(FATAL_ERROR "[Mason] Could not find mason.ini for package ${_PACKAGE} ${_VERSION}")
+ endif()
+
+ set(MASON_PACKAGE_${_PACKAGE}_PREFIX "${_INSTALL_PATH}" CACHE STRING "${_PACKAGE} ${_INSTALL_PATH}" FORCE)
+ mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_PREFIX)
+
+ # Load the configuration from the ini file
+ file(STRINGS "${_INSTALL_PATH}/mason.ini" _CONFIG_FILE)
+ foreach(_LINE IN LISTS _CONFIG_FILE)
+ string(REGEX MATCH "^([a-z_]+) *= *" _KEY "${_LINE}")
+ if (_KEY)
+ string(LENGTH "${_KEY}" _KEY_LENGTH)
+ string(SUBSTRING "${_LINE}" ${_KEY_LENGTH} -1 _VALUE)
+ string(REGEX REPLACE ";.*$" "" _VALUE "${_VALUE}") # Trim trailing commas
+ string(REPLACE "{prefix}" "${_INSTALL_PATH}" _VALUE "${_VALUE}")
+ string(STRIP "${_VALUE}" _VALUE)
+ string(REPLACE "=" "" _KEY "${_KEY}")
+ string(STRIP "${_KEY}" _KEY)
+ string(TOUPPER "${_KEY}" _KEY)
+ if(_KEY STREQUAL "INCLUDE_DIRS" OR _KEY STREQUAL "STATIC_LIBS" )
+ separate_arguments(_VALUE)
+ endif()
+ set(MASON_PACKAGE_${_PACKAGE}_${_KEY} "${_VALUE}" CACHE STRING "${_PACKAGE} ${_KEY}" FORCE)
+ mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_${_KEY})
+ endif()
+ endforeach()
+
+ # Compare version in the package to catch errors early on
+ if(NOT _VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_VERSION)
+ message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has version '${MASON_PACKAGE_${_PACKAGE}_VERSION}', but required '${_VERSION}'")
+ endif()
+
+ if(NOT _PACKAGE STREQUAL MASON_PACKAGE_${_PACKAGE}_NAME)
+ message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has name '${MASON_PACKAGE_${_PACKAGE}_NAME}', but required '${_NAME}'")
+ endif()
+
+ if(NOT _HEADER_ONLY)
+ if(NOT MASON_PLATFORM STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM)
+ message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform '${MASON_PACKAGE_${_PACKAGE}_PLATFORM}', but required '${MASON_PLATFORM}'")
+ endif()
+
+ if(NOT MASON_PLATFORM_VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION)
+ message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform version '${MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION}', but required '${MASON_PLATFORM_VERSION}'")
+ endif()
+ endif()
+
+ # Concatenate the static libs and libraries
+ set(_LIBRARIES)
+ list(APPEND _LIBRARIES ${MASON_PACKAGE_${_PACKAGE}_STATIC_LIBS} ${MASON_PACKAGE_${_PACKAGE}_LDFLAGS})
+ set(MASON_PACKAGE_${_PACKAGE}_LIBRARIES "${_LIBRARIES}" CACHE STRING "${_PACKAGE} _LIBRARIES" FORCE)
+ mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARIES)
+
+ if(NOT _HEADER_ONLY)
+ string(REGEX MATCHALL "(^| +)-L *([^ ]+)" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LDFLAGS}")
+ string(REGEX REPLACE "(^| +)-L *" "\\1" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}")
+ set(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" CACHE STRING "${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" FORCE)
+ mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS)
+ endif()
+
+ # Store invocation ID to prevent different versions of the same package in one invocation
+ set(MASON_PACKAGE_${_PACKAGE}_INVOCATION "${MASON_INVOCATION}" CACHE INTERNAL "${_PACKAGE} invocation ID" FORCE)
+ endif()
+endfunction()
+
+macro(target_add_mason_package _TARGET _VISIBILITY _PACKAGE)
+ if (NOT MASON_PACKAGE_${_PACKAGE}_INVOCATION)
+ message(FATAL_ERROR "[Mason] Package ${_PACKAGE} has not been initialized yet")
+ endif()
+
+ target_include_directories(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_INCLUDE_DIRS}")
+ target_compile_definitions(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_DEFINITIONS}")
+ target_compile_options(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_OPTIONS}")
+ target_link_libraries(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_LIBRARIES}")
+endmacro()
+
+# Setup
+
+string(RANDOM LENGTH 16 MASON_INVOCATION)
+
+# Read environment variables if CMake is run in command mode
+if (CMAKE_ARGC)
+ set(MASON_PLATFORM "$ENV{MASON_PLATFORM}")
+ set(MASON_PLATFORM_VERSION "$ENV{MASON_PLATFORM_VERSION}")
+ set(MASON_PACKAGE_DIR "$ENV{MASON_PACKAGE_DIR}")
+ set(MASON_REPOSITORY "$ENV{MASON_REPOSITORY}")
+endif()
+
+# Directory where Mason packages are located; typically ends with mason_packages
+if (NOT MASON_PACKAGE_DIR)
+ set(MASON_PACKAGE_DIR "${CMAKE_SOURCE_DIR}/mason_packages")
+endif()
+
+# URL prefix of where packages are located.
+if (NOT MASON_REPOSITORY)
+ set(MASON_REPOSITORY "https://mason-binaries.s3.amazonaws.com")
+endif()
+
+mason_detect_platform()
+
+# Execute commands if CMake is run in command mode
+if (CMAKE_ARGC)
+ # Collect remaining arguments for passing to mason_use
+ set(_MASON_ARGS)
+ foreach(I RANGE 4 ${CMAKE_ARGC})
+ list(APPEND _MASON_ARGS "${CMAKE_ARGV${I}}")
+ endforeach()
+
+ # Install the package
+ mason_use(${_MASON_ARGS})
+
+ # Optionally print variables
+ if(DEFINED MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3})
+ # CMake can't write to stdout with message()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3}}")
+ endif()
+endif()
diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake
index 4002257bb4..8c9aa0fe8f 100644
--- a/cmake/mbgl.cmake
+++ b/cmake/mbgl.cmake
@@ -6,27 +6,12 @@ if (NOT MBGL_PLATFORM)
endif()
endif()
-if (NOT MASON_PLATFORM)
- set(MASON_PLATFORM "${MBGL_PLATFORM}")
+find_program(NodeJS_EXECUTABLE NAMES nodejs node)
+if (NOT NodeJS_EXECUTABLE)
+ message(FATAL_ERROR "Could not find Node.js")
endif()
-set(MBGL_GENERATED ${CMAKE_BINARY_DIR}/generated/${CMAKE_CFG_INTDIR})
-
-if(NOT EXISTS ${CMAKE_SOURCE_DIR}/node_modules/node-cmake/FindNodeJS.cmake)
- message(FATAL_ERROR "Can't find node-cmake")
-endif()
-
-# Load Node.js
-set(NodeJS_CXX_STANDARD 14 CACHE INTERNAL "Use C++14" FORCE)
-set(NodeJS_DOWNLOAD ON CACHE INTERNAL "Download node.js sources" FORCE)
-set(NodeJS_USE_CLANG_STDLIB OFF CACHE BOOL "Don't use libc++ by default" FORCE)
-list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/node_modules/node-cmake)
-find_package(NodeJS)
-
-find_program(npm_EXECUTABLE
- NAMES npm
- PATHS ${NodeJS_ROOT_DIR})
-
+find_program(npm_EXECUTABLE NAMES npm)
if (NOT npm_EXECUTABLE)
message(FATAL_ERROR "Could not find npm")
endif()
@@ -56,7 +41,7 @@ endfunction()
# Run submodule update
message(STATUS "Updating submodules...")
execute_process(
- COMMAND git submodule update --init .mason mapbox-gl-js
+ COMMAND git submodule update --init mapbox-gl-js
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/mapbox-gl-js/node_modules")
@@ -70,14 +55,14 @@ endif()
# Add target for running submodule update during builds
add_custom_target(
update-submodules ALL
- COMMAND git submodule update --init .mason mapbox-gl-js
+ COMMAND git submodule update --init mapbox-gl-js
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
COMMENT "Updating submodules..."
)
# Run npm install for both directories, and add custom commands, and a target that depends on them.
_npm_install("${CMAKE_SOURCE_DIR}" mapbox-gl-native update-submodules)
-_npm_install("${CMAKE_SOURCE_DIR}/mapbox-gl-js" mapbox-gl-js "${CMAKE_SOURCE_DIR}/node_modules/.mapbox-gl-native.stamp")
+_npm_install("${CMAKE_SOURCE_DIR}/mapbox-gl-js/test/integration" mapbox-gl-js "${CMAKE_SOURCE_DIR}/node_modules/.mapbox-gl-native.stamp")
add_custom_target(
npm-install ALL
DEPENDS "${CMAKE_SOURCE_DIR}/node_modules/.mapbox-gl-js.stamp"
diff --git a/cmake/node.cmake b/cmake/node.cmake
index ea28e86106..b9a4f68ecc 100644
--- a/cmake/node.cmake
+++ b/cmake/node.cmake
@@ -1,7 +1,15 @@
+# Load Node.js
+include(cmake/NodeJS.cmake)
+nodejs_init()
+
add_nodejs_module(mbgl-node
platform/node/src/node_mapbox_gl_native.cpp
)
+# 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
@@ -41,7 +49,7 @@ target_add_mason_package(mbgl-node PRIVATE geojson)
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
+ COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:mbgl-node> ${CMAKE_SOURCE_DIR}/lib/mapbox_gl_native.node
)
mbgl_platform_node()
diff --git a/cmake/shaders.cmake b/cmake/shaders.cmake
deleted file mode 100644
index a9ded80a6c..0000000000
--- a/cmake/shaders.cmake
+++ /dev/null
@@ -1,32 +0,0 @@
-function(add_shader VAR name)
- set(shader_build_cmd ${NodeJS_EXECUTABLE} ${CMAKE_SOURCE_DIR}/scripts/build-shaders.js)
- set(shader_file_prefix ${CMAKE_SOURCE_DIR}/mapbox-gl-js/shaders)
- set(shader_source_prefix ${MBGL_GENERATED}/include/mbgl/shader)
-
- add_custom_command(
- OUTPUT ${shader_source_prefix}/${name}.hpp
- COMMAND ${shader_build_cmd} ${name} ${shader_file_prefix} ${shader_source_prefix}
- DEPENDS npm-install
- DEPENDS ${CMAKE_SOURCE_DIR}/scripts/build-shaders.js
- DEPENDS ${shader_file_prefix}/${name}.vertex.glsl
- DEPENDS ${shader_file_prefix}/${name}.fragment.glsl
- DEPENDS ${shader_file_prefix}/_prelude.vertex.glsl
- DEPENDS ${shader_file_prefix}/_prelude.fragment.glsl
- VERBATIM
- )
- set(${VAR} ${${VAR}} ${shader_source_prefix}/${name}.hpp PARENT_SCOPE)
-endfunction()
-
-add_shader(MBGL_SHADER_FILES circle)
-add_shader(MBGL_SHADER_FILES collision_box)
-add_shader(MBGL_SHADER_FILES debug)
-add_shader(MBGL_SHADER_FILES fill)
-add_shader(MBGL_SHADER_FILES fill_outline)
-add_shader(MBGL_SHADER_FILES fill_outline_pattern)
-add_shader(MBGL_SHADER_FILES fill_pattern)
-add_shader(MBGL_SHADER_FILES line)
-add_shader(MBGL_SHADER_FILES line_pattern)
-add_shader(MBGL_SHADER_FILES line_sdf)
-add_shader(MBGL_SHADER_FILES raster)
-add_shader(MBGL_SHADER_FILES symbol_icon)
-add_shader(MBGL_SHADER_FILES symbol_sdf)
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index 5d2b63d13f..59929bbb70 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -48,8 +48,11 @@ set(MBGL_TEST_FILES
test/src/mbgl/test/fake_file_source.hpp
test/src/mbgl/test/fixture_log_observer.cpp
test/src/mbgl/test/fixture_log_observer.hpp
+ test/src/mbgl/test/getrss.cpp
+ test/src/mbgl/test/getrss.hpp
test/src/mbgl/test/stub_file_source.cpp
test/src/mbgl/test/stub_file_source.hpp
+ test/src/mbgl/test/stub_geometry_tile_feature.hpp
test/src/mbgl/test/stub_layer_observer.hpp
test/src/mbgl/test/stub_style_observer.hpp
test/src/mbgl/test/stub_tile_observer.hpp
@@ -68,15 +71,22 @@ set(MBGL_TEST_FILES
test/storage/offline_download.test.cpp
test/storage/online_file_source.test.cpp
test/storage/resource.test.cpp
+ test/storage/sqlite.test.cpp
# style/conversion
test/style/conversion/function.test.cpp
test/style/conversion/geojson_options.test.cpp
+ test/style/conversion/layer.test.cpp
test/style/conversion/stringify.test.cpp
# style
test/style/filter.test.cpp
- test/style/functions.test.cpp
+
+ # style/function
+ test/style/function/camera_function.test.cpp
+ test/style/function/source_function.test.cpp
+
+ # style
test/style/group_by_layout.test.cpp
test/style/paint_property.test.cpp
test/style/source.test.cpp
diff --git a/cmake/test.cmake b/cmake/test.cmake
index fc7a22874c..2a83a633c0 100644
--- a/cmake/test.cmake
+++ b/cmake/test.cmake
@@ -14,7 +14,6 @@ target_include_directories(mbgl-test
PRIVATE test/include
PRIVATE test/src
PRIVATE platform/default
- PRIVATE ${MBGL_GENERATED}/include
)
target_link_libraries(mbgl-test
diff --git a/common/ca-bundle.crt b/common/ca-bundle.crt
index 9794dfb70f..256da1ff70 100644
--- a/common/ca-bundle.crt
+++ b/common/ca-bundle.crt
@@ -1,130 +1,23 @@
##
-## ca-bundle.crt -- Bundle of CA Root Certificates
+## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Tue Apr 22 08:29:31 2014
+## Certificate data from Mozilla as of: Fri Jan 27 10:57:10 2017 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
-## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
+## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
## an Apache+mod_ssl webserver for SSL client authentication.
## Just configure this file as the SSLCACertificateFile.
##
+## Conversion done with mk-ca-bundle.pl version 1.27.
+## SHA256: dffa79e6aa993f558e82884abf7bb54bf440ab66ee91d82a27a627f6f2a4ace4
+##
-GTE CyberTrust Global Root
-==========================
------BEGIN CERTIFICATE-----
-MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg
-Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG
-A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz
-MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL
-Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0
-IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u
-sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql
-HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID
-AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW
-M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF
-NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
------END CERTIFICATE-----
-
-Thawte Server CA
-================
------BEGIN CERTIFICATE-----
-MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
-DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
-dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE
-AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j
-b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV
-BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u
-c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG
-A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0
-ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl
-/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7
-1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR
-MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J
-GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ
-GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc=
------END CERTIFICATE-----
-
-Thawte Premium Server CA
-========================
------BEGIN CERTIFICATE-----
-MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT
-DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs
-dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE
-AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl
-ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT
-AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU
-VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2
-aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ
-cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2
-aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh
-Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/
-qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm
-SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf
-8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t
-UCemDaYj+bvLpgcUQg==
------END CERTIFICATE-----
-
-Equifax Secure CA
-=================
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE
-ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
-MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT
-B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR
-fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW
-8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG
-A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE
-CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG
-A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS
-spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB
-Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961
-zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB
-BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
-70+sB3c4
------END CERTIFICATE-----
-
-Verisign Class 3 Public Primary Certification Authority
-=======================================================
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx
-FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow
-XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
-IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
-f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
-hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA
-TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah
-WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf
-Tqj/ZA1k
------END CERTIFICATE-----
-
-Verisign Class 3 Public Primary Certification Authority - G2
-============================================================
------BEGIN CERTIFICATE-----
-MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT
-MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
-eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
-dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT
-MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy
-eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln
-biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz
-dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO
-FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71
-lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB
-MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT
-1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD
-Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9
------END CERTIFICATE-----
-
GlobalSign Root CA
==================
-----BEGIN CERTIFICATE-----
@@ -168,63 +61,6 @@ BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----
-ValiCert Class 1 VA
-===================
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
-b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
-bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy
-MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
-d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg
-UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
-LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi
-GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm
-DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG
-lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX
-icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP
-Orf1LXLI
------END CERTIFICATE-----
-
-ValiCert Class 2 VA
-===================
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
-b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
-bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
-MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
-d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg
-UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
-LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC
-CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf
-ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ
-SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV
-UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8
-W9ViH0Pd
------END CERTIFICATE-----
-
-RSA Root Certificate 1
-======================
------BEGIN CERTIFICATE-----
-MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp
-b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
-YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh
-bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw
-MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0
-d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg
-UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0
-LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td
-3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H
-BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs
-3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF
-V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r
-on+jjBXu
------END CERTIFICATE-----
-
Verisign Class 3 Public Primary Certification Authority - G3
============================================================
-----BEGIN CERTIFICATE-----
@@ -249,57 +85,6 @@ xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa
t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----
-Verisign Class 4 Public Primary Certification Authority - G3
-============================================================
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV
-UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv
-cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy
-dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv
-cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg
-Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS
-tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM
-8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW
-Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX
-Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
-j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt
-mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
-fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd
-RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG
-UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
------END CERTIFICATE-----
-
-Entrust.net Secure Server CA
-============================
------BEGIN CERTIFICATE-----
-MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV
-BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg
-cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl
-ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG
-A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi
-eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p
-dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ
-aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5
-gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw
-ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw
-CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l
-dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
-bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
-dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw
-NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow
-HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
-BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN
-Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9
-n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
------END CERTIFICATE-----
-
Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
@@ -345,40 +130,6 @@ Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H
RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
-Equifax Secure Global eBusiness CA
-==================================
------BEGIN CERTIFICATE-----
-MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
-RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp
-bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx
-HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds
-b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV
-PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN
-qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn
-hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
-BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs
-MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN
-I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY
-NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
------END CERTIFICATE-----
-
-Equifax Secure eBusiness CA 1
-=============================
------BEGIN CERTIFICATE-----
-MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
-RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB
-LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE
-ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz
-IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ
-1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a
-IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk
-MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW
-Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF
-AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5
-lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
-KpYrtWKmpj29f5JZzVoqgrI3eQ==
------END CERTIFICATE-----
-
AddTrust Low-Value Services Root
================================
-----BEGIN CERTIFICATE-----
@@ -501,27 +252,6 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----
-RSA Security 2048 v3
-====================
------BEGIN CERTIFICATE-----
-MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK
-ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy
-MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb
-BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7
-Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb
-WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH
-KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP
-+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/
-MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E
-FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY
-v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj
-0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj
-VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395
-nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA
-pKnXwiJPZ9d37CAFYd4=
------END CERTIFICATE-----
-
GeoTrust Global CA
==================
-----BEGIN CERTIFICATE-----
@@ -624,59 +354,6 @@ gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm
X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
-----END CERTIFICATE-----
-America Online Root Certification Authority 1
-=============================================
------BEGIN CERTIFICATE-----
-MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
-QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG
-A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
-T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG
-v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z
-DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh
-sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP
-8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T
-AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z
-o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf
-GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF
-VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft
-3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g
-Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
-sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
------END CERTIFICATE-----
-
-America Online Root Certification Authority 2
-=============================================
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT
-QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG
-A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg
-T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD
-ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en
-fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8
-f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO
-qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN
-RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0
-gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn
-6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid
-FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6
-Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj
-B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op
-aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY
-T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p
-+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg
-JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy
-zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO
-ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh
-1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf
-GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff
-Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP
-cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk=
------END CERTIFICATE-----
-
Visa eCommerce Root
===================
-----BEGIN CERTIFICATE-----
@@ -931,77 +608,6 @@ EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
llpwrN9M
-----END CERTIFICATE-----
-Staat der Nederlanden Root CA
-=============================
------BEGIN CERTIFICATE-----
-MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE
-ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g
-Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w
-HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh
-bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt
-vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P
-jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca
-C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth
-vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6
-22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV
-HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v
-dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN
-BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR
-EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw
-MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y
-nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
-iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
------END CERTIFICATE-----
-
-TDC Internet Root CA
-====================
------BEGIN CERTIFICATE-----
-MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE
-ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx
-NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu
-ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j
-xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL
-znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc
-5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6
-otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI
-AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM
-VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM
-MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC
-AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe
-UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G
-CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m
-gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
-2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb
-O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU
-Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l
------END CERTIFICATE-----
-
-UTN DATACorp SGC Root CA
-========================
------BEGIN CERTIFICATE-----
-MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE
-BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl
-IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ
-BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa
-MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w
-HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy
-dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys
-raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo
-wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA
-9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv
-33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud
-DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9
-BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD
-LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3
-DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
-Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0
-I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx
-EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP
-DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI
------END CERTIFICATE-----
-
UTN USERFirst Hardware Root CA
==============================
-----BEGIN CERTIFICATE-----
@@ -1082,99 +688,6 @@ IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
-----END CERTIFICATE-----
-NetLock Notary (Class A) Root
-=============================
------BEGIN CERTIFICATE-----
-MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI
-EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
-dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j
-ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX
-DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH
-EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD
-VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz
-cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM
-D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ
-z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC
-/tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7
-tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6
-4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG
-A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC
-Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv
-bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
-IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn
-LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0
-ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz
-IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh
-IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu
-b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh
-bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg
-Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp
-bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5
-ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP
-ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB
-CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr
-KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM
-8CgHrTwXZoi1/baI
------END CERTIFICATE-----
-
-NetLock Business (Class B) Root
-===============================
------BEGIN CERTIFICATE-----
-MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT
-CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
-BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg
-VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD
-VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv
-bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg
-VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S
-o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr
-1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV
-HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ
-RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh
-dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0
-ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv
-c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg
-YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
-c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz
-Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA
-bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl
-IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2
-YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj
-cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM
-43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR
-stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI
------END CERTIFICATE-----
-
-NetLock Express (Class C) Root
-==============================
------BEGIN CERTIFICATE-----
-MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT
-CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV
-BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD
-KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ
-BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6
-dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j
-ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB
-jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z
-W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63
-euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw
-DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN
-RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn
-YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB
-IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i
-aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0
-ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
-ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo
-dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y
-emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k
-IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ
-UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg
-YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2
-xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW
-gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A==
------END CERTIFICATE-----
-
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
@@ -1482,54 +995,6 @@ vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
oKfN5XozNmr6mis=
-----END CERTIFICATE-----
-TURKTRUST Certificate Services Provider Root 1
-==============================================
------BEGIN CERTIFICATE-----
-MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP
-MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0
-acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx
-MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg
-U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB
-TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC
-aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX
-yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i
-Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ
-8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4
-W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME
-BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46
-sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE
-q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy
-B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY
-nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H
------END CERTIFICATE-----
-
-TURKTRUST Certificate Services Provider Root 2
-==============================================
------BEGIN CERTIFICATE-----
-MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
-MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
-QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN
-MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr
-dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G
-A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
-acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe
-LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI
-x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g
-QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr
-5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB
-AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G
-A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt
-Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
-Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+
-hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P
-9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5
-UrbnBEI=
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -1799,30 +1264,6 @@ FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
-IGC/A
-=====
------BEGIN CERTIFICATE-----
-MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD
-VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE
-Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy
-MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI
-EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT
-STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2
-TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW
-So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy
-HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd
-frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ
-tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB
-egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC
-iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK
-q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q
-MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg
-Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI
-lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF
-0mBWWg==
------END CERTIFICATE-----
-
Security Communication EV RootCA1
=================================
-----BEGIN CERTIFICATE-----
@@ -1929,117 +1370,6 @@ PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----
-AC Ra\xC3\xADz Certic\xC3\xA1mara S.A.
-======================================
------BEGIN CERTIFICATE-----
-MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT
-AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg
-LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w
-HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+
-U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh
-IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B
-AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN
-yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU
-2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3
-4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP
-2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm
-8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf
-HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa
-Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK
-5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b
-czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g
-ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF
-BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug
-cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf
-AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX
-EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v
-/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3
-MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4
-3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk
-eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f
-/RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h
-RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU
-Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==
------END CERTIFICATE-----
-
-TC TrustCenter Class 2 CA II
-============================
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
-REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
-IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw
-MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
-c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE
-AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw
-IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2
-xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ
-Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u
-SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB
-/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB
-7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
-Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
-cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
-SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G
-dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ
-KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj
-TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP
-JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk
-vQ==
------END CERTIFICATE-----
-
-TC TrustCenter Class 3 CA II
-============================
------BEGIN CERTIFICATE-----
-MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC
-REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy
-IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw
-MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1
-c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE
-AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W
-yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo
-6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ
-uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk
-2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB
-/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB
-7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90
-Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU
-cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i
-SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
-TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE
-O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8
-yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9
-IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal
-092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc
-5A==
------END CERTIFICATE-----
-
-TC TrustCenter Universal CA I
-=============================
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC
-REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
-IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN
-MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg
-VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw
-JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC
-qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv
-xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw
-ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O
-gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j
-BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG
-1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy
-vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3
-ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
-ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a
-7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
------END CERTIFICATE-----
-
Deutsche Telekom Root CA 2
==========================
-----BEGIN CERTIFICATE-----
@@ -2062,28 +1392,6 @@ dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
Cm26OWMohpLzGITY+9HPBVZkVw==
-----END CERTIFICATE-----
-ComSign Secured CA
-==================
------BEGIN CERTIFICATE-----
-MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE
-AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w
-NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD
-QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs
-49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH
-7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB
-kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1
-9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw
-AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t
-U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA
-j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC
-AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a
-BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp
-FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP
-51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
-OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
------END CERTIFICATE-----
-
Cybertrust Global Root
======================
-----BEGIN CERTIFICATE-----
@@ -2165,78 +1473,6 @@ LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M
dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI=
-----END CERTIFICATE-----
-Buypass Class 2 CA 1
-====================
------BEGIN CERTIFICATE-----
-MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
-QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2
-MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
-c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M
-cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83
-0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4
-0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R
-uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC
-MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P
-AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV
-1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt
-7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2
-fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w
-wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
------END CERTIFICATE-----
-
-Buypass Class 3 CA 1
-====================
------BEGIN CERTIFICATE-----
-MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU
-QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1
-MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh
-c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx
-ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0
-n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia
-AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c
-1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC
-MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P
-AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7
-pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA
-EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5
-htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj
-el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
------END CERTIFICATE-----
-
-EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1
-==========================================================================
------BEGIN CERTIFICATE-----
-MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF
-bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg
-QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe
-Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p
-ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt
-IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by
-X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b
-gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr
-eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ
-TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy
-Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn
-uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI
-qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm
-ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0
-Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
-/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW
-Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t
-FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm
-zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k
-XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT
-bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU
-RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK
-1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt
-2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ
-Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9
-AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
------END CERTIFICATE-----
-
certSIGN ROOT CA
================
-----BEGIN CERTIFICATE-----
@@ -2431,7 +1667,7 @@ AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
-----END CERTIFICATE-----
NetLock Arany (Class Gold) Főtanúsítvány
-============================================
+========================================
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G
A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610
@@ -2486,58 +1722,6 @@ IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm
66+KAQ==
-----END CERTIFICATE-----
-CA Disig
-========
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK
-QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw
-MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz
-bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm
-GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD
-Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo
-hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt
-ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w
-gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P
-AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz
-aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff
-ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa
-BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t
-WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3
-mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
-CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K
-ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA
-4Z7CRneC9VkGjCFMhwnN5ag=
------END CERTIFICATE-----
-
-Juur-SK
-=======
------BEGIN CERTIFICATE-----
-MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA
-c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw
-DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG
-SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy
-aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf
-TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC
-+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw
-UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa
-Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF
-MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD
-HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh
-AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA
-cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr
-AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw
-cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
-FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G
-A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo
-ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL
-abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678
-IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh
-Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2
-yyqcjg==
------END CERTIFICATE-----
-
Hongkong Post Root CA 1
=======================
-----BEGIN CERTIFICATE-----
@@ -2610,22 +1794,6 @@ MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o
tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA==
-----END CERTIFICATE-----
-Verisign Class 3 Public Primary Certification Authority
-=======================================================
------BEGIN CERTIFICATE-----
-MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx
-FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5
-IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow
-XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz
-IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA
-A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94
-f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol
-hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky
-CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX
-bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/
-D/xwzoiQ
------END CERTIFICATE-----
-
Microsec e-Szigno Root CA 2009
==============================
-----BEGIN CERTIFICATE-----
@@ -2650,28 +1818,6 @@ yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi
LXpUq3DDfSJlgnCW
-----END CERTIFICATE-----
-E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi
-===================================================
------BEGIN CERTIFICATE-----
-MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG
-EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz
-ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3
-MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0
-cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u
-aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY
-8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y
-jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI
-JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk
-9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD
-AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG
-SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d
-F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq
-D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4
-Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq
-fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX
------END CERTIFICATE-----
-
GlobalSign Root CA - R3
=======================
-----BEGIN CERTIFICATE-----
@@ -3009,7 +2155,7 @@ Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
-----END CERTIFICATE-----
Certinomis - Autorité Racine
-=============================
+============================
-----BEGIN CERTIFICATE-----
MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg
@@ -3039,64 +2185,6 @@ wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/
vgt2Fl43N+bYdJeimUV5
-----END CERTIFICATE-----
-Root CA Generalitat Valenciana
-==============================
------BEGIN CERTIFICATE-----
-MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE
-ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290
-IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3
-WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE
-CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2
-F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B
-ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ
-D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte
-JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB
-AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n
-dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB
-ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl
-AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA
-YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy
-AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA
-aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt
-AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA
-YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu
-AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA
-OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0
-dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV
-BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G
-A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S
-b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh
-TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz
-Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63
-NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH
-iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt
-+GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM=
------END CERTIFICATE-----
-
-A-Trust-nQual-03
-================
------BEGIN CERTIFICATE-----
-MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE
-Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
-a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R
-dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw
-RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0
-ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1
-c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA
-zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n
-yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE
-SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4
-iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V
-cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV
-eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40
-ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr
-sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd
-JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
-mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6
-ahq97BvIxYSazQ==
------END CERTIFICATE-----
-
TWCA Root Certification Authority
=================================
-----BEGIN CERTIFICATE-----
@@ -3864,3 +2952,1092 @@ TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9
61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G
3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
+
+QuoVadis Root CA 1 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE
+PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm
+PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6
+Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN
+ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l
+g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV
+7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX
+9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f
+iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg
+t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI
+hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
+MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3
+GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct
+Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP
++V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh
+3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa
+wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6
+O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0
+FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV
+hMJKzRwuJIczYOXD
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 2 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh
+ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY
+NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t
+oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o
+MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l
+V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo
+L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ
+sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD
+6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh
+lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI
+hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K
+pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9
+x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz
+dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X
+U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw
+mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD
+zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN
+JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr
+O3jtZsSOeWmD3n+M
+-----END CERTIFICATE-----
+
+QuoVadis Root CA 3 G3
+=====================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG
+A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv
+b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN
+MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg
+RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286
+IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL
+Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe
+6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3
+I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U
+VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7
+5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi
+Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM
+dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt
+rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI
+hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS
+t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ
+TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du
+DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib
+Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD
+hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX
+0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW
+dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2
+PpxxVJkES/1Y+Zj0
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw
+IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw
+MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH
+35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq
+bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw
+VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP
+YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn
+lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO
+w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv
+0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz
+d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW
+hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M
+jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
+IhNzbM8m9Yop5w==
+-----END CERTIFICATE-----
+
+DigiCert Assured ID Root G3
+===========================
+-----BEGIN CERTIFICATE-----
+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
+VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ
+BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb
+RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs
+KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF
+UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy
+YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy
+1vUhZscv6pZjamVFkpUBtA==
+-----END CERTIFICATE-----
+
+DigiCert Global Root G2
+=======================
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw
+HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx
+MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
+dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ
+kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO
+3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV
+BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM
+UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB
+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu
+5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr
+F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U
+WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH
+QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/
+iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+
+DigiCert Global Root G3
+=======================
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD
+VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw
+MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k
+aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C
+AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O
+YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp
+Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y
+3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34
+VOKa5Vt8sycX
+-----END CERTIFICATE-----
+
+DigiCert Trusted Root G4
+========================
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw
+HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1
+MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp
+pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o
+k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa
+vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
+QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6
+MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm
+mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7
+f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH
+dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8
+oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
+ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr
+yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy
+7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah
+ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN
+5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb
+/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa
+5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK
+G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP
+82Z+
+-----END CERTIFICATE-----
+
+WoSign
+======
+-----BEGIN CERTIFICATE-----
+MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g
+QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ
+BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
+vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO
+CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX
+2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5
+KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR
++ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez
+EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk
+lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2
+8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY
+yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C
+AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R
+8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1
+LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq
+T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj
+y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC
+2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes
+5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/
+EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh
+mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx
+kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi
+kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w==
+-----END CERTIFICATE-----
+
+WoSign China
+============
+-----BEGIN CERTIFICATE-----
+MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv
+geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD
+VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k
+8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5
+uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85
+dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5
+Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy
+b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc
+76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m
++Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6
+yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX
+GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA
+A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6
+yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY
+r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115
+j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A
+kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97
+qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y
+jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB
+ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv
+T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO
+kI26oQ==
+-----END CERTIFICATE-----
+
+COMODO RSA Certification Authority
+==================================
+-----BEGIN CERTIFICATE-----
+MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE
+BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG
+A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC
+R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE
+ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn
+dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ
+FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+
+5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG
+x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX
+2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL
+OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3
+sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C
+GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5
+WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
+FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt
+rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+
+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg
+tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW
+sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp
+pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA
+zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq
+ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52
+7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I
+LaZRfyHBNVOFBkpdn627G190
+-----END CERTIFICATE-----
+
+USERTrust RSA Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE
+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE
+BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK
+ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz
+0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j
+Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn
+RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O
++T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq
+/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE
+Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM
+lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8
+yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+
+eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
+BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW
+FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ
+7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ
+Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM
+8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi
+FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi
+yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c
+J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw
+sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx
+Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9
+-----END CERTIFICATE-----
+
+USERTrust ECC Certification Authority
+=====================================
+-----BEGIN CERTIFICATE-----
+MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
+aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2
+0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez
+nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV
+HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB
+HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu
+9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R4
+===========================
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl
+OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P
+AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV
+MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF
+JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q=
+-----END CERTIFICATE-----
+
+GlobalSign ECC Root CA - R5
+===========================
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb
+R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD
+EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6
+SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS
+h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx
+uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7
+yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+
+Staat der Nederlanden Root CA - G3
+==================================
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC
+TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l
+ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y
+olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t
+x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy
+EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K
+Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur
+mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5
+1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp
+07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo
+FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE
+41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB
+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu
+yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
+U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq
+KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1
+v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA
+8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b
+8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r
+mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq
+1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI
+JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV
+tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk=
+-----END CERTIFICATE-----
+
+Staat der Nederlanden EV Root CA
+================================
+-----BEGIN CERTIFICATE-----
+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE
+CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g
+RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M
+MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl
+cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk
+SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW
+O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r
+0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8
+Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV
+XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr
+08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV
+0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd
+74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx
+fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa
+ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu
+c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq
+5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN
+b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN
+f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi
+5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4
+WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK
+DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy
+eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg==
+-----END CERTIFICATE-----
+
+IdenTrust Commercial Root CA 1
+==============================
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS
+b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES
+MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB
+IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld
+hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/
+mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi
+1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C
+XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl
+3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy
+NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV
+WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg
+xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix
+uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI
+hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
+6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg
+ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt
+ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV
+YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX
+feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro
+kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe
+2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz
+Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R
+cGzM7vRX+Bi6hG6H
+-----END CERTIFICATE-----
+
+IdenTrust Public Sector Root CA 1
+=================================
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG
+EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv
+ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV
+UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS
+b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy
+P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6
+Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI
+rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf
+qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS
+mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn
+ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh
+LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v
+iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL
+4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B
+Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw
+DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
+t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A
+mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt
+GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt
+m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx
+NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4
+Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI
+ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC
+ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ
+3Wl9af0AVqW3rLatt8o+Ae+c
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - G2
+=========================================
+-----BEGIN CERTIFICATE-----
+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV
+BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy
+bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug
+b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw
+HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT
+DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx
+OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP
+/vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz
+HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU
+s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y
+TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx
+AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6
+0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z
+iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi
+nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+
+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO
+e4pIb4tF9g==
+-----END CERTIFICATE-----
+
+Entrust Root Certification Authority - EC1
+==========================================
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn
+YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw
+FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs
+LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg
+dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy
+AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef
+9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h
+vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8
+kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
+-----END CERTIFICATE-----
+
+CFCA EV ROOT
+============
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE
+CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB
+IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw
+MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD
+DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV
+BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD
+7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN
+uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW
+ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7
+xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f
+py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K
+gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol
+hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ
+tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf
+BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
+ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q
+ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua
+4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG
+E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX
+BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn
+aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy
+PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX
+kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C
+ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
+-----END CERTIFICATE-----
+
+TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H5
+====================================================
+-----BEGIN CERTIFICATE-----
+MIIEJzCCAw+gAwIBAgIHAI4X/iQggTANBgkqhkiG9w0BAQsFADCBsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFNMEsGA1UECgxEVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4xQjBABgNVBAMMOVTDnFJLVFJVU1Qg
+RWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSBINTAeFw0xMzA0MzAw
+ODA3MDFaFw0yMzA0MjgwODA3MDFaMIGxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMU0w
+SwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnE
+n2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBFbGVrdHJvbmlrIFNlcnRp
+ZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApCUZ4WWe60ghUEoI5RHwWrom/4NZzkQqL/7hzmAD/I0Dpe3/a6i6zDQGn1k19uwsu537
+jVJp45wnEFPzpALFp/kRGml1bsMdi9GYjZOHp3GXDSHHmflS0yxjXVW86B8BSLlg/kJK9siArs1m
+ep5Fimh34khon6La8eHBEJ/rPCmBp+EyCNSgBbGM+42WAA4+Jd9ThiI7/PS98wl+d+yG6w8z5UNP
+9FR1bSmZLmZaQ9/LXMrI5Tjxfjs1nQ/0xVqhzPMggCTTV+wVunUlm+hkS7M0hO8EuPbJbKoCPrZV
+4jI3X/xml1/N1p7HIL9Nxqw/dV8c7TKcfGkAaZHjIxhT6QIDAQABo0IwQDAdBgNVHQ4EFgQUVpkH
+HtOsDGlktAxQR95DLL4gwPswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJ5FdnsXSDLyOIspve6WSk6BGLFRRyDN0GSxDsnZAdkJzsiZ3GglE9Rc8qPo
+BP5yCccLqh0lVX6Wmle3usURehnmp349hQ71+S4pL+f5bFgWV1Al9j4uPqrtd3GqqpmWRgqujuwq
+URawXs3qZwQcWDD1YIq9pr1N5Za0/EKJAWv2cMhQOQwt1WbZyNKzMrcbGW3LM/nfpeYVhDfwwvJl
+lpKQd/Ct9JDpEXjXk4nAPQu6KfTomZ1yju2dL+6SfaHx/126M2CFYv4HAqGEVka+lgqaE9chTLd8
+B59OTj+RdPsnnRHM3eaxynFNExc5JsUpISuTKWqW+qtB4Uu2NQvAmxU=
+-----END CERTIFICATE-----
+
+TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6
+====================================================
+-----BEGIN CERTIFICATE-----
+MIIEJjCCAw6gAwIBAgIGfaHyZeyKMA0GCSqGSIb3DQEBCwUAMIGxMQswCQYDVQQGEwJUUjEPMA0G
+A1UEBwwGQW5rYXJhMU0wSwYDVQQKDERUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls
+acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjFCMEAGA1UEAww5VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIEg2MB4XDTEzMTIxODA5
+MDQxMFoXDTIzMTIxNjA5MDQxMFowgbExCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExTTBL
+BgNVBAoMRFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBCaWxpxZ9pbSBHw7x2ZW5sacSf
+aSBIaXptZXRsZXJpIEEuxZ4uMUIwQAYDVQQDDDlUw5xSS1RSVVNUIEVsZWt0cm9uaWsgU2VydGlm
+aWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLEgSDYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQCdsGjW6L0UlqMACprx9MfMkU1xeHe59yEmFXNRFpQJRwXiM/VomjX/3EsvMsew7eKC5W/a
+2uqsxgbPJQ1BgfbBOCK9+bGlprMBvD9QFyv26WZV1DOzXPhDIHiTVRZwGTLmiddk671IUP320EED
+wnS3/faAz1vFq6TWlRKb55cTMgPp1KtDWxbtMyJkKbbSk60vbNg9tvYdDjTu0n2pVQ8g9P0pu5Fb
+HH3GQjhtQiht1AH7zYiXSX6484P4tZgvsycLSF5W506jM7NE1qXyGJTtHB6plVxiSvgNZ1GpryHV
++DKdeboaX+UEVU0TRv/yz3THGmNtwx8XEsMeED5gCLMxAgMBAAGjQjBAMB0GA1UdDgQWBBTdVRcT
+9qzoSCHK77Wv0QAy7Z6MtTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQsFAAOCAQEAb1gNl0OqFlQ+v6nfkkU/hQu7VtMMUszIv3ZnXuaqs6fvuay0EBQNdH49ba3R
+fdCaqaXKGDsCQC4qnFAUi/5XfldcEQlLNkVS9z2sFP1E34uXI9TDwe7UU5X+LEr+DXCqu4svLcsy
+o4LyVN/Y8t3XSHLuSqMplsNEzm61kod2pLv0kmzOLBQJZo6NrRa1xxsJYTvjIKIDgI6tflEATseW
+hvtDmHd9KMeP2Cpu54Rvl0EpABZeTeIT6lnAY2c6RPuY/ATTMHKm9ocJV612ph1jmv3XZch4gyt1
+O6VbuA1df74jrlZVlFjvH4GMKrLN5ptjnhi85WsGtAuYSyher4hYyw==
+-----END CERTIFICATE-----
+
+Certinomis - Root CA
+====================
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjETMBEGA1UEChMK
+Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAbBgNVBAMTFENlcnRpbm9taXMg
+LSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMzMTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIx
+EzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRD
+ZXJ0aW5vbWlzIC0gUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQos
+P5L2fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJflLieY6pOo
+d5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQVWZUKxkd8aRi5pwP5ynap
+z8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDFTKWrteoB4owuZH9kb/2jJZOLyKIOSY00
+8B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09x
+RLWtwHkziOC/7aOgFLScCbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE
+6OXWk6RiwsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJwx3t
+FvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SGm/lg0h9tkQPTYKbV
+PZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4F2iw4lNVYC2vPsKD2NkJK/DAZNuH
+i5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZngWVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGj
+YzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I
+6tNxIqSSaHh02TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/0KGRHCwPT5iV
+WVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWwF6YSjNRieOpWauwK0kDDPAUw
+Pk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZSg081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAX
+lCOotQqSD7J6wWAsOMwaplv/8gzjqh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJ
+y29SWwNyhlCVCNSNh4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9
+Iff/ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8Vbtaw5Bng
+DwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwjY/M50n92Uaf0yKHxDHYi
+I0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nM
+cyrDflOR1m749fPH0FFNjkulW+YZFzvWgQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVr
+hkIGuUE=
+-----END CERTIFICATE-----
+
+OISTE WISeKey Global Root GB CA
+===============================
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBtMQswCQYDVQQG
+EwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAw
+MzJaFw0zOTEyMDExNTEwMzFaMG0xCzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEds
+b2JhbCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3HEokKtaX
+scriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGxWuR51jIjK+FTzJlFXHtP
+rby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk
+9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNku7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4o
+Qnc/nSMbsrY9gBQHTC5P99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvg
+GUpuuy9rM2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZI
+hvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrghcViXfa43FK8+5/ea4n32cZiZBKpD
+dHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0
+VQreUGdNZtGn//3ZwLWoo4rOZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEui
+HZeeevJuQHHfaPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
+Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
+-----END CERTIFICATE-----
+
+Certification Authority of WoSign G2
+====================================
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQayXaioidfLwPBbOxemFFRDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQG
+EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxLTArBgNVBAMTJENlcnRpZmljYXRpb24g
+QXV0aG9yaXR5IG9mIFdvU2lnbiBHMjAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMFgx
+CzAJBgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEtMCsGA1UEAxMkQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgb2YgV29TaWduIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvsXEoCKASU+/2YcRxlPhuw+9YH+v9oIOH9ywjj2X4FA8jzrvZjtFB5sg+OPXJYY1kBai
+XW8wGQiHC38Gsp1ij96vkqVg1CuAmlI/9ZqD6TRay9nVYlzmDuDfBpgOgHzKtB0TiGsOqCR3A9Du
+W/PKaZE1OVbFbeP3PU9ekzgkyhjpJMuSA93MHD0JcOQg5PGurLtzaaNjOg9FD6FKmsLRY6zLEPg9
+5k4ot+vElbGs/V6r+kHLXZ1L3PR8du9nfwB6jdKgGlxNIuG12t12s9R23164i5jIFFTMaxeSt+BK
+v0mUYQs4kI9dJGwlezt52eJ+na2fmKEG/HgUYFf47oB3sQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU+mCp62XF3RYUCE4MD42b4Pdkr2cwDQYJKoZI
+hvcNAQELBQADggEBAFfDejaCnI2Y4qtAqkePx6db7XznPWZaOzG73/MWM5H8fHulwqZm46qwtyeY
+P0nXYGdnPzZPSsvxFPpahygc7Y9BMsaV+X3avXtbwrAh449G3CE4Q3RM+zD4F3LBMvzIkRfEzFg3
+TgvMWvchNSiDbGAtROtSjFA9tWwS1/oJu2yySrHFieT801LYYRf+epSEj3m2M1m6D8QL4nCgS3gu
++sif/a+RZQp4OBXllxcU3fngLDT4ONCEIgDAFFEYKwLcMFrw6AF8NTojrwjkr6qOKEJJLvD1mTS+
+7Q9LGOHSJDy7XUe3IfKN0QqZjuNuPq1w4I+5ysxugTH2e5x6eeRncRg=
+-----END CERTIFICATE-----
+
+CA WoSign ECC Root
+==================
+-----BEGIN CERTIFICATE-----
+MIICCTCCAY+gAwIBAgIQaEpYcIBr8I8C+vbe6LCQkDAKBggqhkjOPQQDAzBGMQswCQYDVQQGEwJD
+TjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMTEkNBIFdvU2lnbiBFQ0MgUm9v
+dDAeFw0xNDExMDgwMDU4NThaFw00NDExMDgwMDU4NThaMEYxCzAJBgNVBAYTAkNOMRowGAYDVQQK
+ExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAxMSQ0EgV29TaWduIEVDQyBSb290MHYwEAYHKoZI
+zj0CAQYFK4EEACIDYgAE4f2OuEMkq5Z7hcK6C62N4DrjJLnSsb6IOsq/Srj57ywvr1FQPEd1bPiU
+t5v8KB7FVMxjnRZLU8HnIKvNrCXSf4/CwVqCXjCLelTOA7WRf6qU0NGKSMyCBSah1VES1ns2o0Iw
+QDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqv3VWqP2h4syhf3R
+MluARZPzA7gwCgYIKoZIzj0EAwMDaAAwZQIxAOSkhLCB1T2wdKyUpOgOPQB0TKGXa/kNUTyh2Tv0
+Daupn75OcsqF1NnstTJFGG+rrQIwfcf3aWMvoeGY7xMQ0Xk/0f7qO3/eVvSQsRUR2LIiFdAvwyYu
+a/GRspBl9JrmkO5K
+-----END CERTIFICATE-----
+
+SZAFIR ROOT CA2
+===============
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQELBQAwUTELMAkG
+A1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6ZW5pb3dhIFMuQS4xGDAWBgNV
+BAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkwNzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJ
+BgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYD
+VQQDDA9TWkFGSVIgUk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5Q
+qEvNQLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT3PSQ1hNK
+DJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw3gAeqDRHu5rr/gsUvTaE
+2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr63fE9biCloBK0TXC5ztdyO4mTp4CEHCdJ
+ckm1/zuVnsHMyAHs6A6KCpbns6aH5db5BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwi
+ieDhZNRnvDF5YTy7ykHNXGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P
+AQH/BAQDAgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsFAAOC
+AQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw8PRBEew/R40/cof5
+O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOGnXkZ7/e7DDWQw4rtTw/1zBLZpD67
+oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCPoky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul
+4+vJhaAlIDf7js4MNIThPIGyd05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6
++/NNIxuZMzSgLvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
+-----END CERTIFICATE-----
+
+Certum Trusted Network CA 2
+===========================
+-----BEGIN CERTIFICATE-----
+MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCBgDELMAkGA1UE
+BhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1
+bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29y
+ayBDQSAyMCIYDzIwMTExMDA2MDgzOTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQ
+TDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENB
+IDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWADGSdhhuWZGc/IjoedQF9
+7/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+o
+CgCXhVqqndwpyeI1B+twTUrWwbNWuKFBOJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40b
+Rr5HMNUuctHFY9rnY3lEfktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2p
+uTRZCr+ESv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1mo130
+GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02isx7QBlrd9pPPV3WZ
+9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOWOZV7bIBaTxNyxtd9KXpEulKkKtVB
+Rgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgezTv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pye
+hizKV/Ma5ciSixqClnrDvFASadgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vM
+BhBgu4M1t15n3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZI
+hvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQF/xlhMcQSZDe28cmk4gmb3DW
+Al45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTfCVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuA
+L55MYIR4PSFk1vtBHxgP58l1cb29XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMo
+clm2q8KMZiYcdywmdjWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tM
+pkT/WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jbAoJnwTnb
+w3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksqP/ujmv5zMnHCnsZy4Ypo
+J/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Kob7a6bINDd82Kkhehnlt4Fj1F4jNy3eFm
+ypnTycUm/Q1oBEauttmbjL4ZvrHG8hnjXALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLX
+is7VmFxWlgPF7ncGNf/P5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7
+zAYspsbiDrW5viSP
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions RootCA 2015
+=======================================================
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcT
+BkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0
+aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
+YXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAx
+MTIxWjCBpjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMg
+QWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNV
+BAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIw
+MTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDC+Kk/G4n8PDwEXT2QNrCROnk8Zlrv
+bTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+eh
+iGsxr/CL0BgzuNtFajT0AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+
+6PAQZe104S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06CojXd
+FPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV9Cz82XBST3i4vTwr
+i5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrDgfgXy5I2XdGj2HUb4Ysn6npIQf1F
+GQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2
+fu/Z8VFRfS0myGlZYeCsargqNhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9mu
+iNX6hME6wGkoLfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVdctA4GGqd83EkVAswDQYJKoZI
+hvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0IXtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+
+D1hYc2Ryx+hFjtyp8iY/xnmMsVMIM4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrM
+d/K4kPFox/la/vot9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+y
+d+2VZ5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/eaj8GsGsVn
+82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnhX9izjFk0WaSrT2y7Hxjb
+davYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQl033DlZdwJVqwjbDG2jJ9SrcR5q+ss7F
+Jej6A7na+RZukYT1HCjI/CbM1xyQVqdfbzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVt
+J94Cj8rDtSvK6evIIVM4pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGa
+JI7ZjnHKe7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0vm9q
+p/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+
+Hellenic Academic and Research Institutions ECC RootCA 2015
+===========================================================
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzANBgNVBAcTBkF0
+aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9u
+cyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
+aCBJbnN0aXR1dGlvbnMgRUNDIFJvb3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEw
+MzcxMlowgaoxCzAJBgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmlj
+IEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUQwQgYD
+VQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIEVDQyBSb290
+Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKgQehLgoRc4vgxEZmGZE4JJS+dQS8KrjVP
+dJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJajq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoK
+Vlp8aQuqgAkkbH7BRqNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O
+BBYEFLQiC4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaeplSTA
+GiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7SofTUwJCA3sS61kFyjn
+dc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+
+Certplus Root CA G1
+===================
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUAMD4xCzAJBgNV
+BAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTAe
+Fw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhD
+ZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHN
+r49aiZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt6kuJPKNx
+Qv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP0FG7Yn2ksYyy/yARujVj
+BYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTv
+LRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDEEW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2
+z4QTd28n6v+WZxcIbekN1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc
+4nBvCGrch2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCTmehd
+4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV4EJQeIQEQWGw9CEj
+jy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPOWftwenMGE9nTdDckQQoRb5fc5+R+
+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0G
+A1UdDgQWBBSowcCbkahDFXxdBie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHY
+lwuBsTANBgkqhkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
+66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7/SMNkPX0XtPG
+YX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BSS7CTKtQ+FjPlnsZlFT5kOwQ/
+2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F
+6ALEUz65noe8zDUa3qHpimOHZR4RKttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilX
+CNQ314cnrUlZp5GrRHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWe
+tUNy6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEVV/xuZDDC
+VRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5g4VCXA9DO2pJNdWY9BW/
++mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl++O/QmueD6i9a5jc2NvLi6Td11n0bt3+
+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
+-----END CERTIFICATE-----
+
+Certplus Root CA G2
+===================
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4xCzAJBgNVBAYT
+AkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjAeFw0x
+NDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0
+cGx1czEcMBoGA1UEAwwTQ2VydHBsdXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IA
+BM0PW1aC3/BFGtat93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uN
+Am8xIk0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMB8GA1Ud
+IwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqGSM49BAMDA2gAMGUCMHD+sAvZ94OX7PNV
+HdTcswYO/jOYnYs5kGuUIe22113WTNchp+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjl
+vPl5adytRSv3tjFzzAalU5ORGpOucGpnutee5WEaXw==
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G1
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcx
+MB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7fa
+Yp6bwiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX/uMftk87
+ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR077F9jAHiOH3BX2pfJLKO
+YheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGPuY4zbGneWK2gDqdkVBFpRGZPTBKnjix9
+xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLxp2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO
+9z0M+Yo0FMT7MzUj8czxKselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq
+3ywgsNw2TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+WG+Oi
+n6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPwvFEVVJSmdz7QdFG9
+URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYYEQRVzXR7z2FwefR7LFxckvzluFqr
+TJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUl0YhVyE12jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/Px
+N3DlCPaTKbYwDQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
+PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kfgLMtMrpkZ2Cv
+uVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbSFXJfLkur1J1juONI5f6ELlgK
+n0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLh
+X4SPgPL0DTatdrOjteFkdjpY3H1PXlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80
+nR14SohWZ25g/4/Ii+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcm
+GS3tTAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L9109S5zvE/
+bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/KyPu1svf0OnWZzsD2097+o
+4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJAwSQiumPv+i2tCqjI40cHLI5kqiPAlxA
+OXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj1oxx
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G2
+====================
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUAMEAxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEcy
+MB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoM
+CU9wZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+
+Ntmh/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78eCbY2albz
+4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/61UWY0jUJ9gNDlP7ZvyCV
+eYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fEFY8ElggGQgT4hNYdvJGmQr5J1WqIP7wt
+UdGejeBSzFfdNTVY27SPJIjki9/ca1TSgSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz
+3GIZ38i1MH/1PCZ1Eb3XG7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj
+3CzMpSZyYhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaHvGOz
+9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4t/bQWVyJ98LVtZR0
+0dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/gh7PU3+06yzbXfZqfUAkBXKJOAGT
+y3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUajn6QiL35okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59
+M4PLuG53hq8wDQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
+Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0nXGEL8pZ0keI
+mUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qTRmTFAHneIWv2V6CG1wZy7HBG
+S4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpTwm+bREx50B1ws9efAvSyB7DH5fitIw6mVskp
+EndI2S9G/Tvw/HRwkqWOOAgfZDC2t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ
+6e18CL13zSdkzJTaTkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97kr
+gCf2o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU3jg9CcCo
+SmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eAiN1nE28daCSLT7d0geX0
+YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14fWKGVyasvc0rQLW6aWQ9VGHgtPFGml4vm
+u7JwqkwR3v98KzfUetF3NI/n+UL3PIEMS1IK
+-----END CERTIFICATE-----
+
+OpenTrust Root CA G3
+====================
+-----BEGIN CERTIFICATE-----
+MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5UcnVzdCBSb290IENBIEczMB4X
+DTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9w
+ZW5UcnVzdDEdMBsGA1UEAwwUT3BlblRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAARK7liuTcpm3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5B
+ta1doYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4GA1UdDwEB
+/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAf
+BgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAKBggqhkjOPQQDAwNpADBmAjEAj6jcnboM
+BBf6Fek9LykBl7+BFjNAk2z8+e2AcG+qj9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta
+3U1fJAuwACEl74+nBCZx4nxp5V2a+EEfOzmTk51V6s2N8fvB
+-----END CERTIFICATE-----
+
+ISRG Root X1
+============
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UE
+BhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2VhcmNoIEdyb3VwMRUwEwYDVQQD
+EwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQG
+EwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMT
+DElTUkcgUm9vdCBYMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54r
+Vygch77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+0TM8ukj1
+3Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6UA5/TR5d8mUgjU+g4rk8K
+b4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sWT8KOEUt+zwvo/7V3LvSye0rgTBIlDHCN
+Aymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyHB5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ
+4Q7e2RCOFvu396j3x+UCB5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf
+1b0SHzUvKBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWnOlFu
+hjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTnjh8BCNAw1FtxNrQH
+usEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbwqHyGO0aoSCqI3Haadr8faqU9GY/r
+OPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CIrU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY
+9umbbjANBgkqhkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
+ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ3BebYhtF8GaV
+0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KKNFtY2PwByVS5uCbMiogziUwt
+hDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJw
+TdwJx4nLCgdNbOhdjsnvzqvHu7UrTkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nx
+e5AW0wdeRlN8NwdCjNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZA
+JzVcoyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq4RgqsahD
+YVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPAmRGunUHBcnWEvgJBQl9n
+JEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57demyPxgcYxn/eR44/KJ4EBs+lVDR3veyJ
+m+kXQ99b21/+jh5Xos1AnX5iItreGCc=
+-----END CERTIFICATE-----
+
+AC RAIZ FNMT-RCM
+================
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNVBAYT
+AkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTAeFw0wODEw
+MjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJD
+TTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBALpxgHpMhm5/yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcf
+qQgfBBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAzWHFctPVr
+btQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxFtBDXaEAUwED653cXeuYL
+j2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z374jNUUeAlz+taibmSXaXvMiwzn15Cou
+08YfxGyqxRxqAQVKL9LFwag0Jl1mpdICIfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mw
+WsXmo8RZZUc1g16p6DULmbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnT
+tOmlcYF7wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peSMKGJ
+47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2ZSysV4999AeU14EC
+ll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMetUqIJ5G+GR4of6ygnXYMgrwTJbFaa
+i0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FPd9xf3E6Jobd2Sn9R2gzL+HYJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1o
+dHRwOi8vd3d3LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1RXxlDPiyN8+s
+D8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYMLVN0V2Ue1bLdI4E7pWYjJ2cJ
+j+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrT
+Qfv6MooqtyuGC2mDOL7Nii4LcK2NJpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW
++YJF1DngoABd15jmfZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7
+Ixjp6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp1txyM/1d
+8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B9kiABdcPUXmsEKvU7ANm
+5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wokRqEIr9baRRmW1FMdW4R58MD3R++Lj8UG
+rp1MYp3/RgT408m2ECVAdf4WqslKYIYvuu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
+-----END CERTIFICATE-----
+
+Amazon Root CA 1
+================
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAxMB4XDTE1
+MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALJ4gHHKeNXjca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgH
+FzZM9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qwIFAGbHrQ
+gLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6VOujw5H5SNz/0egwLX0t
+dHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L93FcXmn/6pUCyziKrlA4b9v7LWIbxcce
+VOF34GfID5yHI9Y/QCB/IIDEgEw+OyQmjgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3
+DQEBCwUAA4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDIU5PM
+CCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUsN+gDS63pYaACbvXy
+8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vvo/ufQJVtMVT8QtPHRh8jrdkPSHCa
+2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2
+xJNDd2ZhwLnoQdeXeGADbkpyrqXRfboQnoZsG4q5WTP468SQvvG5
+-----END CERTIFICATE-----
+
+Amazon Root CA 2
+================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwFADA5MQswCQYD
+VQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAyMB4XDTE1
+MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpv
+bjEZMBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAK2Wny2cSkxKgXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4
+kHbZW0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg1dKmSYXp
+N+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K8nu+NQWpEjTj82R0Yiw9
+AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvd
+fLC6HM783k81ds8P+HgfajZRRidhW+mez/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAEx
+kv8LV/SasrlX6avvDXbR8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSS
+btqDT6ZjmUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz7Mt0
+Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6+XUyo05f7O0oYtlN
+c/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI0u1ufm8/0i2BWSlmy5A5lREedCf+
+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSw
+DPBMMPQFWAJI/TPlUq9LhONmUjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oA
+A7CXDpO8Wqj2LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kSk5Nrp+gvU5LE
+YFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl7uxMMne0nxrpS10gxdr9HIcW
+xkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygmbtmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQ
+gj9sAq+uEjonljYE1x2igGOpm/HlurR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbW
+aQbLU8uz/mtBzUF+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoV
+Yh63n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE76KlXIx3
+KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H9jVlpNMKVv/1F2Rs76gi
+JUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT4PsJYGw=
+-----END CERTIFICATE-----
+
+Amazon Root CA 3
+================
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSAzMB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZB
+f8ANm+gBG1bG8lKlui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjr
+Zt6jQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSrttvXBp43
+rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkrBqWTrBqYaGFy+uGh0Psc
+eGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteMYyRIHN8wfdVoOw==
+-----END CERTIFICATE-----
+
+Amazon Root CA 4
+================
+-----BEGIN CERTIFICATE-----
+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5MQswCQYDVQQG
+EwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24gUm9vdCBDQSA0MB4XDTE1MDUy
+NjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZ
+MBcGA1UEAxMQQW1hem9uIFJvb3QgQ0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN
+/sGKe0uoe0ZLY7Bi9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri
+83BkM6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WBMAoGCCqGSM49BAMDA2gA
+MGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlwCkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1
+AE47xDqUEpHJWEadIRNyp4iciuRMStuW1KyLa2tJElMzrdfkviT8tQp21KW8EA==
+-----END CERTIFICATE-----
+
+LuxTrust Global Root 2
+======================
+-----BEGIN CERTIFICATE-----
+MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQELBQAwRjELMAkG
+A1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNVBAMMFkx1eFRydXN0IEdsb2Jh
+bCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUwMzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEW
+MBQGA1UECgwNTHV4VHJ1c3QgUy5BLjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCC
+AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wm
+Kb3FibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTemhfY7RBi2
+xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1EMShduxq3sVs35a0VkBC
+wGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsnXpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm
+1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkm
+FRseTJIpgp7VkoGSQXAZ96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niF
+wpN6cj5mj5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4gDEa/
+a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+8kPREd8vZS9kzl8U
+ubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2jX5t/Lax5Gw5CMZdjpPuKadUiDTSQ
+MC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmHhFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB
+/zBCBgNVHSAEOzA5MDcGByuBKwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5
+Lmx1eHRydXN0Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT
++Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQELBQADggIBAGoZ
+FO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9BzZAcg4atmpZ1gDlaCDdLnIN
+H2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTOjFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW
+7MM3LGVYvlcAGvI1+ut7MV3CwRI9loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIu
+ZY+kt9J/Z93I055cqqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWA
+VWe+2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/JEAdemrR
+TxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKrezrnK+T+Tb/mjuuqlPpmt
+/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQfLSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc
+7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31I
+iyBMz2TWuJdGsE7RKlY6oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
+-----END CERTIFICATE-----
diff --git a/include/mbgl/annotation/annotation.hpp b/include/mbgl/annotation/annotation.hpp
index a72c65b8c4..de83d24712 100644
--- a/include/mbgl/annotation/annotation.hpp
+++ b/include/mbgl/annotation/annotation.hpp
@@ -4,6 +4,7 @@
#include <mbgl/util/variant.hpp>
#include <mbgl/util/color.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <cstdint>
#include <vector>
@@ -29,17 +30,17 @@ using ShapeAnnotationGeometry = variant<
class LineAnnotation {
public:
ShapeAnnotationGeometry geometry;
- style::PropertyValue<float> opacity { 1.0f };
+ style::DataDrivenPropertyValue<float> opacity { 1.0f };
style::PropertyValue<float> width { 1.0f };
- style::PropertyValue<Color> color { Color::black() };
+ style::DataDrivenPropertyValue<Color> color { Color::black() };
};
class FillAnnotation {
public:
ShapeAnnotationGeometry geometry;
- style::PropertyValue<float> opacity { 1.0f };
- style::PropertyValue<Color> color { Color::black() };
- style::PropertyValue<Color> outlineColor {};
+ style::DataDrivenPropertyValue<float> opacity { 1.0f };
+ style::DataDrivenPropertyValue<Color> color { Color::black() };
+ style::DataDrivenPropertyValue<Color> outlineColor {};
};
// An annotation whose type and properties are sourced from a style layer.
diff --git a/include/mbgl/gl/gl.hpp b/include/mbgl/gl/gl.hpp
index 425f78bcba..7521b4c80d 100644
--- a/include/mbgl/gl/gl.hpp
+++ b/include/mbgl/gl/gl.hpp
@@ -41,7 +41,7 @@ struct Error : std::runtime_error {
void checkError(const char *cmd, const char *file, int line);
#ifndef NDEBUG
-#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
+#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { ::mbgl::gl::checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
#else
#define MBGL_CHECK_ERROR(cmd) (cmd)
#endif
diff --git a/include/mbgl/map/backend.hpp b/include/mbgl/map/backend.hpp
index 0468449155..4a43921c0b 100644
--- a/include/mbgl/map/backend.hpp
+++ b/include/mbgl/map/backend.hpp
@@ -41,24 +41,9 @@ protected:
virtual void activate() = 0;
virtual void deactivate() = 0;
-private:
- const std::unique_ptr<gl::Context> context;
+ std::unique_ptr<gl::Context> context;
friend class BackendScope;
};
-class BackendScope {
-public:
- BackendScope(Backend& backend_) : backend(backend_) {
- backend.activate();
- }
-
- ~BackendScope() {
- backend.deactivate();
- }
-
-private:
- Backend& backend;
-};
-
} // namespace mbgl
diff --git a/include/mbgl/map/backend_scope.hpp b/include/mbgl/map/backend_scope.hpp
new file mode 100644
index 0000000000..5a207e6ac4
--- /dev/null
+++ b/include/mbgl/map/backend_scope.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+namespace mbgl {
+
+class Backend;
+
+class BackendScope {
+public:
+ BackendScope(Backend&);
+ ~BackendScope();
+
+private:
+ BackendScope* priorScope;
+ BackendScope* nextScope;
+ Backend& backend;
+};
+
+} // namespace mbgl
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index c80420371d..95a82ebd74 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -9,6 +9,7 @@
#include <mbgl/util/size.hpp>
#include <mbgl/annotation/annotation.hpp>
#include <mbgl/style/transition_options.hpp>
+#include <mbgl/map/camera.hpp>
#include <cstdint>
#include <string>
@@ -86,22 +87,23 @@ public:
void flyTo(const CameraOptions&, const AnimationOptions&);
// Position
- void moveBy(const ScreenCoordinate&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<EdgeInsets>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const Duration& = Duration::zero());
+ void moveBy(const ScreenCoordinate&, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<EdgeInsets>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, const AnimationOptions& = {});
LatLng getLatLng(optional<EdgeInsets> = {}) const;
void resetPosition(optional<EdgeInsets> = {});
// Scale
- void scaleBy(double ds, optional<ScreenCoordinate> = {}, const Duration& = Duration::zero());
- void setScale(double scale, optional<ScreenCoordinate> = {}, const Duration& = Duration::zero());
+ void scaleBy(double ds, optional<ScreenCoordinate> = {}, const AnimationOptions& = {});
+ void setScale(double scale, optional<ScreenCoordinate> = {}, const AnimationOptions& = {});
double getScale() const;
- void setZoom(double zoom, const Duration& = Duration::zero());
- void setZoom(double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void setZoom(double zoom, const AnimationOptions& = {});
+ void setZoom(double zoom, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setZoom(double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
double getZoom() const;
- void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void setLatLngZoom(const LatLng&, double zoom, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
CameraOptions cameraForLatLngBounds(const LatLngBounds&, optional<EdgeInsets>) const;
CameraOptions cameraForLatLngs(const std::vector<LatLng>&, optional<EdgeInsets>) const;
void resetZoom();
@@ -111,17 +113,17 @@ public:
double getMaxZoom() const;
// Rotation
- void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& = Duration::zero());
- void setBearing(double degrees, const Duration& = Duration::zero());
- void setBearing(double degrees, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setBearing(double degrees, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
+ void setBearing(double degrees, const AnimationOptions& = {});
+ void setBearing(double degrees, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setBearing(double degrees, optional<EdgeInsets>, const AnimationOptions& = {});
double getBearing() const;
- void resetNorth(const Duration& = Milliseconds(500));
- void resetNorth(optional<EdgeInsets>, const Duration& = Milliseconds(500));
+ void resetNorth(const AnimationOptions& = {{mbgl::Milliseconds(500)}});
+ void resetNorth(optional<EdgeInsets>, const AnimationOptions& = {{mbgl::Milliseconds(500)}});
// Pitch
- void setPitch(double pitch, const Duration& = Duration::zero());
- void setPitch(double pitch, optional<ScreenCoordinate>, const Duration& = Duration::zero());
+ void setPitch(double pitch, const AnimationOptions& = {});
+ void setPitch(double pitch, optional<ScreenCoordinate>, const AnimationOptions& = {});
double getPitch() const;
// North Orientation
diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp
index b8f5e1167e..9262e0a1bc 100644
--- a/include/mbgl/storage/default_file_source.hpp
+++ b/include/mbgl/storage/default_file_source.hpp
@@ -29,13 +29,15 @@ public:
bool supportsOptionalRequests() const override {
return true;
}
-
+
void setAPIBaseURL(const std::string&);
std::string getAPIBaseURL() const;
void setAccessToken(const std::string&);
std::string getAccessToken() const;
+ void setResourceTransform(std::function<std::string(Resource::Kind, std::string&&)>);
+
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
/*
@@ -113,6 +115,25 @@ public:
*/
void setOfflineMapboxTileCountLimit(uint64_t) const;
+ /*
+ * Pause file request activity.
+ *
+ * If pause is called then no revalidation or network request activity
+ * will occur.
+ *
+ * Note: Calling pause and then calling getAPIBaseURL or getAccessToken
+ * will lock the thread that those calls are made on.
+ */
+ void pause();
+
+ /*
+ * Resume file request activity.
+ *
+ * Calling resume will unpause the file source and process any tasks that
+ * expired while the file source was paused.
+ */
+ void resume();
+
// For testing only.
void put(const Resource&, const Response&);
@@ -122,6 +143,8 @@ private:
const std::unique_ptr<util::Thread<Impl>> thread;
const std::unique_ptr<FileSource> assetFileSource;
const std::unique_ptr<FileSource> localFileSource;
+ std::string cachedBaseURL = mbgl::util::API_BASE_URL;
+ std::string cachedAccessToken;
};
} // namespace mbgl
diff --git a/include/mbgl/storage/online_file_source.hpp b/include/mbgl/storage/online_file_source.hpp
index 9c7feceb47..51cfc5a2a1 100644
--- a/include/mbgl/storage/online_file_source.hpp
+++ b/include/mbgl/storage/online_file_source.hpp
@@ -12,10 +12,14 @@ public:
void setAPIBaseURL(const std::string& t) { apiBaseURL = t; }
std::string getAPIBaseURL() const { return apiBaseURL; }
-
+
void setAccessToken(const std::string& t) { accessToken = t; }
std::string getAccessToken() const { return accessToken; }
+ using ResourceTransform =
+ std::function<std::unique_ptr<AsyncRequest>(Resource::Kind, std::string&&, std::function<void(std::string&&)>)>;
+ void setResourceTransform(ResourceTransform&& cb);
+
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
private:
diff --git a/include/mbgl/storage/response.hpp b/include/mbgl/storage/response.hpp
index 448423c1cb..32fe4e0c8a 100644
--- a/include/mbgl/storage/response.hpp
+++ b/include/mbgl/storage/response.hpp
@@ -35,7 +35,7 @@ public:
optional<std::string> etag;
bool isFresh() const {
- return !expires || *expires > util::now();
+ return expires ? *expires > util::now() : !error;
}
};
@@ -53,7 +53,7 @@ public:
// An error message from the request handler, e.g. a server message or a system message
// informing the user about the reason for the failure.
std::string message;
-
+
optional<Timestamp> retryAfter;
public:
diff --git a/include/mbgl/style/conversion/data_driven_property_value.hpp b/include/mbgl/style/conversion/data_driven_property_value.hpp
new file mode 100644
index 0000000000..83f44fdb27
--- /dev/null
+++ b/include/mbgl/style/conversion/data_driven_property_value.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <mbgl/style/data_driven_property_value.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/style/conversion/function.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <class T>
+struct Converter<DataDrivenPropertyValue<T>> {
+ template <class V>
+ Result<DataDrivenPropertyValue<T>> operator()(const V& value) const {
+ if (isUndefined(value)) {
+ return {};
+ } else if (!isObject(value)) {
+ Result<T> constant = convert<T>(value);
+ if (!constant) {
+ return constant.error();
+ }
+ return DataDrivenPropertyValue<T>(*constant);
+ } else if (!objectMember(value, "property")) {
+ Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
+ if (!function) {
+ return function.error();
+ }
+ return DataDrivenPropertyValue<T>(*function);
+ } else {
+ Result<CompositeFunction<T>> composite = convert<CompositeFunction<T>>(value);
+ if (composite) {
+ return DataDrivenPropertyValue<T>(*composite);
+ }
+ Result<SourceFunction<T>> source = convert<SourceFunction<T>>(value);
+ if (!source) {
+ return source.error();
+ }
+ return DataDrivenPropertyValue<T>(*source);
+ }
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp
index 3ab91e5bbc..2c4eeb4ac7 100644
--- a/include/mbgl/style/conversion/filter.hpp
+++ b/include/mbgl/style/conversion/filter.hpp
@@ -27,9 +27,9 @@ public:
}
if (*op == "==") {
- return convertBinaryFilter<EqualsFilter>(value);
+ return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value);
} else if (*op == "!=") {
- return convertBinaryFilter<NotEqualsFilter>(value);
+ return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value);
} else if (*op == ">") {
return convertBinaryFilter<GreaterThanFilter>(value);
} else if (*op == ">=") {
@@ -39,9 +39,9 @@ public:
} else if (*op == "<=") {
return convertBinaryFilter<LessThanEqualsFilter>(value);
} else if (*op == "in") {
- return convertSetFilter<InFilter>(value);
+ return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value);
} else if (*op == "!in") {
- return convertSetFilter<NotInFilter>(value);
+ return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value);
} else if (*op == "all") {
return convertCompoundFilter<AllFilter>(value);
} else if (*op == "any") {
@@ -49,32 +49,57 @@ public:
} else if (*op == "none") {
return convertCompoundFilter<NoneFilter>(value);
} else if (*op == "has") {
- return convertUnaryFilter<HasFilter>(value);
+ return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value);
} else if (*op == "!has") {
- return convertUnaryFilter<NotHasFilter>(value);
+ return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value);
}
return Error { "filter operator must be one of \"==\", \"!=\", \">\", \">=\", \"<\", \"<=\", \"in\", \"!in\", \"all\", \"any\", \"none\", \"has\", or \"!has\"" };
}
private:
- Result<Value> normalizeValue(const std::string& key, const optional<Value>& value) const {
+ Result<Value> normalizeValue(const optional<Value>& value) const {
if (!value) {
return Error { "filter expression value must be a boolean, number, or string" };
- } else if (key != "$type") {
+ } else {
return *value;
- } else if (*value == std::string("Point")) {
- return Value(uint64_t(FeatureType::Point));
- } else if (*value == std::string("LineString")) {
- return Value(uint64_t(FeatureType::LineString));
- } else if (*value == std::string("Polygon")) {
- return Value(uint64_t(FeatureType::Polygon));
+ }
+ }
+
+ template <class V>
+ Result<FeatureType> toFeatureType(const V& value) const {
+ optional<std::string> type = toString(value);
+ if (!type) {
+ return Error { "value for $type filter must be a string" };
+ } else if (*type == "Point") {
+ return FeatureType::Point;
+ } else if (*type == "LineString") {
+ return FeatureType::LineString;
+ } else if (*type == "Polygon") {
+ return FeatureType::Polygon;
} else {
return Error { "value for $type filter must be Point, LineString, or Polygon" };
}
}
- template <class FilterType, class V>
+ template <class V>
+ Result<FeatureIdentifier> toFeatureIdentifier(const V& value) const {
+ optional<Value> identifier = toValue(value);
+ if (!identifier) {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ } else {
+ return (*identifier).match(
+ [] (uint64_t t) -> Result<FeatureIdentifier> { return t; },
+ [] ( int64_t t) -> Result<FeatureIdentifier> { return t; },
+ [] ( double t) -> Result<FeatureIdentifier> { return t; },
+ [] (const std::string& t) -> Result<FeatureIdentifier> { return t; },
+ [] (const auto&) -> Result<FeatureIdentifier> {
+ return Error { "filter expression value must be a boolean, number, or string" };
+ });
+ }
+ }
+
+ template <class FilterType, class IdentifierFilterType, class V>
Result<Filter> convertUnaryFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must have 2 elements" };
@@ -85,7 +110,48 @@ private:
return Error { "filter expression key must be a string" };
}
- return FilterType { *key };
+ if (*key == "$id") {
+ return IdentifierFilterType {};
+ } else {
+ return FilterType { *key };
+ }
+ }
+
+ template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
+ Result<Filter> convertEqualityFilter(const V& value) const {
+ if (arrayLength(value) < 3) {
+ return Error { "filter expression must have 3 elements" };
+ }
+
+ optional<std::string> key = toString(arrayMember(value, 1));
+ if (!key) {
+ return Error { "filter expression key must be a string" };
+ }
+
+ if (*key == "$type") {
+ Result<FeatureType> filterValue = toFeatureType(arrayMember(value, 2));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return TypeFilterType { *filterValue };
+
+ } else if (*key == "$id") {
+ Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, 2));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return IdentifierFilterType { *filterValue };
+
+ } else {
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+
+ return FilterType { *key, *filterValue };
+ }
}
template <class FilterType, class V>
@@ -99,7 +165,7 @@ private:
return Error { "filter expression key must be a string" };
}
- Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, 2)));
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, 2)));
if (!filterValue) {
return filterValue.error();
}
@@ -107,7 +173,7 @@ private:
return FilterType { *key, *filterValue };
}
- template <class FilterType, class V>
+ template <class FilterType, class TypeFilterType, class IdentifierFilterType, class V>
Result<Filter> convertSetFilter(const V& value) const {
if (arrayLength(value) < 2) {
return Error { "filter expression must at least 2 elements" };
@@ -118,16 +184,42 @@ private:
return Error { "filter expression key must be a string" };
}
- std::vector<Value> values;
- for (std::size_t i = 2; i < arrayLength(value); ++i) {
- Result<Value> filterValue = normalizeValue(*key, toValue(arrayMember(value, i)));
- if (!filterValue) {
- return filterValue.error();
+ if (*key == "$type") {
+ std::vector<FeatureType> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<FeatureType> filterValue = toFeatureType(arrayMember(value, i));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
}
- values.push_back(*filterValue);
- }
- return FilterType { *key, std::move(values) };
+ return TypeFilterType { std::move(values) };
+
+ } else if (*key == "$id") {
+ std::vector<FeatureIdentifier> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<FeatureIdentifier> filterValue = toFeatureIdentifier(arrayMember(value, i));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return IdentifierFilterType { std::move(values) };
+
+ } else {
+ std::vector<Value> values;
+ for (std::size_t i = 2; i < arrayLength(value); ++i) {
+ Result<Value> filterValue = normalizeValue(toValue(arrayMember(value, i)));
+ if (!filterValue) {
+ return filterValue.error();
+ }
+ values.push_back(*filterValue);
+ }
+
+ return FilterType { *key, std::move(values) };
+ }
}
template <class FilterType, class V>
diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp
index 6a0b67618f..a5979e6799 100644
--- a/include/mbgl/style/conversion/function.hpp
+++ b/include/mbgl/style/conversion/function.hpp
@@ -1,70 +1,382 @@
#pragma once
-#include <mbgl/style/function.hpp>
+#include <mbgl/style/function/camera_function.hpp>
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
+#include <mbgl/util/ignore.hpp>
namespace mbgl {
namespace style {
namespace conversion {
+template <class D, class R, class V>
+Result<std::map<D, R>> convertStops(const V& value) {
+ auto stopsValue = objectMember(value, "stops");
+ if (!stopsValue) {
+ return Error { "function value must specify stops" };
+ }
+
+ if (!isArray(*stopsValue)) {
+ return Error { "function stops must be an array" };
+ }
+
+ if (arrayLength(*stopsValue) == 0) {
+ return Error { "function must have at least one stop" };
+ }
+
+ std::map<D, R> stops;
+ for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
+ const auto& stopValue = arrayMember(*stopsValue, i);
+
+ if (!isArray(stopValue)) {
+ return Error { "function stop must be an array" };
+ }
+
+ if (arrayLength(stopValue) != 2) {
+ return Error { "function stop must have two elements" };
+ }
+
+ Result<D> d = convert<D>(arrayMember(stopValue, 0));
+ if (!d) {
+ return d.error();
+ }
+
+ Result<R> r = convert<R>(arrayMember(stopValue, 1));
+ if (!r) {
+ return r.error();
+ }
+
+ stops.emplace(*d, *r);
+ }
+
+ return stops;
+}
+
+template <class T>
+struct Converter<ExponentialStops<T>> {
+ static constexpr const char * type = "exponential";
+
+ template <class V>
+ Result<ExponentialStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<float, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ auto baseValue = objectMember(value, "base");
+ if (!baseValue) {
+ return ExponentialStops<T>(*stops);
+ }
+
+ optional<float> base = toNumber(*baseValue);
+ if (!base) {
+ return Error { "function base must be a number"};
+ }
+
+ return ExponentialStops<T>(*stops, *base);
+ }
+};
+
+template <class T>
+struct Converter<IntervalStops<T>> {
+ static constexpr const char * type = "interval";
+
+ template <class V>
+ Result<IntervalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<float, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+ return IntervalStops<T>(*stops);
+ }
+};
+
+template <>
+struct Converter<CategoricalValue> {
+ template <class V>
+ Result<CategoricalValue> operator()(const V& value) const {
+ auto b = toBool(value);
+ if (b) {
+ return *b;
+ }
+
+ auto n = toNumber(value);
+ if (n) {
+ return int64_t(*n);
+ }
+
+ auto s = toString(value);
+ if (s) {
+ return *s;
+ }
+
+ return Error { "stop domain value must be a number, string, or boolean" };
+ }
+};
+
+template <class T>
+struct Converter<CategoricalStops<T>> {
+ static constexpr const char * type = "categorical";
+
+ template <class V>
+ Result<CategoricalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CategoricalValue, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+ return CategoricalStops<T>(
+ std::map<CategoricalValue, T>((*stops).begin(), (*stops).end()));
+ }
+};
+
+template <class T>
+struct Converter<IdentityStops<T>> {
+ static constexpr const char * type = "identity";
+
+ template <class V>
+ Result<IdentityStops<T>> operator()(const V&) const {
+ return IdentityStops<T>();
+ }
+};
+
+template <class, class>
+struct StopsConverter;
+
+template <class T, class... Ts>
+struct StopsConverter<T, variant<Ts...>> {
+public:
+ template <class V>
+ Result<variant<Ts...>> operator()(const V& value) const {
+ std::string type = util::Interpolatable<T> ? "exponential" : "interval";
+
+ auto typeValue = objectMember(value, "type");
+ if (typeValue && toString(*typeValue)) {
+ type = *toString(*typeValue);
+ }
+
+ optional<Result<variant<Ts...>>> result;
+
+ // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47226
+ auto tryConvert = [&] (auto* tp) {
+ using Stops = std::decay_t<decltype(*tp)>;
+ if (type == Converter<Stops>::type) {
+ auto stops = convert<Stops>(value);
+ result = stops
+ ? Result<variant<Ts...>>(*stops)
+ : Result<variant<Ts...>>(stops.error());
+ }
+ };
+
+ util::ignore({
+ (tryConvert((Ts*)nullptr), 0)...
+ });
+
+ if (!result) {
+ return Error { "unsupported function type" };
+ }
+
+ return *result;
+ }
+};
+
+template <class T>
+struct Converter<CameraFunction<T>> {
+ template <class V>
+ Result<CameraFunction<T>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "function must be an object" };
+ }
+
+ auto stops = StopsConverter<T, typename CameraFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ return CameraFunction<T>(*stops);
+ }
+};
+
+template <class T, class V>
+Result<optional<T>> convertDefaultValue(const V& value) {
+ auto defaultValueValue = objectMember(value, "default");
+ if (!defaultValueValue) {
+ return {};
+ }
+
+ auto defaultValue = convert<T>(*defaultValueValue);
+ if (!defaultValue) {
+ return Error { "wrong type for \"default\": " + defaultValue.error().message };
+ }
+
+ return *defaultValue;
+}
+
template <class T>
-struct Converter<Function<T>> {
+struct Converter<SourceFunction<T>> {
template <class V>
- Result<Function<T>> operator()(const V& value) const {
+ Result<SourceFunction<T>> operator()(const V& value) const {
if (!isObject(value)) {
return Error { "function must be an object" };
}
- auto stopsValue = objectMember(value, "stops");
- if (!stopsValue) {
- return Error { "function value must specify stops" };
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ return Error { "function must specify property" };
}
- if (!isArray(*stopsValue)) {
- return Error { "function stops must be an array" };
+ auto propertyString = toString(*propertyValue);
+ if (!propertyString) {
+ return Error { "function property must be a string" };
}
- if (arrayLength(*stopsValue) == 0) {
- return Error { "function must have at least one stop" };
+ auto stops = StopsConverter<T, typename SourceFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
}
- std::vector<std::pair<float, T>> stops;
- for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) {
- const auto& stopValue = arrayMember(*stopsValue, i);
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
+ }
- if (!isArray(stopValue)) {
- return Error { "function stop must be an array" };
- }
+ return SourceFunction<T>(*propertyString, *stops, *defaultValue);
+ }
+};
- if (arrayLength(stopValue) != 2) {
- return Error { "function stop must have two elements" };
- }
+template <class S>
+struct CompositeValue : std::pair<float, S> {
+ using std::pair<float, S>::pair;
+};
- optional<float> z = toNumber(arrayMember(stopValue, 0));
- if (!z) {
- return Error { "function stop zoom level must be a number" };
- }
+template <class S>
+struct Converter<CompositeValue<S>> {
+ template <class V>
+ Result<CompositeValue<S>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "stop must be an object" };
+ }
- Result<T> v = convert<T>(arrayMember(stopValue, 1));
- if (!v) {
- return v.error();
- }
+ auto zoomValue = objectMember(value, "zoom");
+ if (!zoomValue) {
+ return Error { "stop must specify zoom" };
+ }
+
+ auto propertyValue = objectMember(value, "value");
+ if (!propertyValue) {
+ return Error { "stop must specify value" };
+ }
+
+ Result<float> z = convert<float>(*zoomValue);
+ if (!z) {
+ return z.error();
+ }
+
+ Result<S> s = convert<S>(*propertyValue);
+ if (!s) {
+ return s.error();
+ }
+
+ return CompositeValue<S> { *z, *s };
+ }
+};
+
+template <class T>
+struct Converter<CompositeExponentialStops<T>> {
+ static constexpr const char * type = "exponential";
- stops.emplace_back(*z, *v);
+ template <class V>
+ Result<CompositeExponentialStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value);
+ if (!stops) {
+ return stops.error();
}
+ auto base = 1.0f;
auto baseValue = objectMember(value, "base");
- if (!baseValue) {
- return Function<T>(stops, 1.0f);
+ if (baseValue && toNumber(*baseValue)) {
+ base = *toNumber(*baseValue);
}
- optional<float> base = toNumber(*baseValue);
- if (!base) {
- return Error { "function base must be a number"};
+ std::map<float, std::map<float, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeExponentialStops<T>(convertedStops, base);
+ }
+};
+
+template <class T>
+struct Converter<CompositeIntervalStops<T>> {
+ static constexpr const char * type = "interval";
+
+ template <class V>
+ Result<CompositeIntervalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<float>, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ std::map<float, std::map<float, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeIntervalStops<T>(convertedStops);
+ }
+};
+
+template <class T>
+struct Converter<CompositeCategoricalStops<T>> {
+ static constexpr const char * type = "categorical";
+
+ template <class V>
+ Result<CompositeCategoricalStops<T>> operator()(const V& value) const {
+ auto stops = convertStops<CompositeValue<CategoricalValue>, T>(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ std::map<float, std::map<CategoricalValue, T>> convertedStops;
+ for (const auto& stop : *stops) {
+ convertedStops[stop.first.first].emplace(stop.first.second, stop.second);
+ }
+
+ return CompositeCategoricalStops<T>(convertedStops);
+ }
+};
+
+template <class T>
+struct Converter<CompositeFunction<T>> {
+ template <class V>
+ Result<CompositeFunction<T>> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "function must be an object" };
+ }
+
+ auto propertyValue = objectMember(value, "property");
+ if (!propertyValue) {
+ return Error { "function must specify property" };
+ }
+
+ auto propertyString = toString(*propertyValue);
+ if (!propertyString) {
+ return Error { "function property must be a string" };
+ }
+
+ auto stops = StopsConverter<T, typename CompositeFunction<T>::Stops>()(value);
+ if (!stops) {
+ return stops.error();
+ }
+
+ auto defaultValue = convertDefaultValue<T>(value);
+ if (!defaultValue) {
+ return defaultValue.error();
}
- return Function<T>(stops, *base);
+ return CompositeFunction<T>(*propertyString, *stops, *defaultValue);
}
};
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp b/include/mbgl/style/conversion/make_property_setters.hpp
index e30359937e..32fa810f0b 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp
+++ b/include/mbgl/style/conversion/make_property_setters.hpp
@@ -77,69 +77,127 @@ auto makePaintPropertySetters() {
std::unordered_map<std::string, PaintPropertySetter<V>> result;
result["fill-antialias"] = makePropertySetter<V>(&FillLayer::setFillAntialias);
+ result["fill-antialias-transition"] = makeTransitionSetter<V>(&FillLayer::setFillAntialiasTransition);
result["fill-opacity"] = makePropertySetter<V>(&FillLayer::setFillOpacity);
+ result["fill-opacity-transition"] = makeTransitionSetter<V>(&FillLayer::setFillOpacityTransition);
result["fill-color"] = makePropertySetter<V>(&FillLayer::setFillColor);
+ result["fill-color-transition"] = makeTransitionSetter<V>(&FillLayer::setFillColorTransition);
result["fill-outline-color"] = makePropertySetter<V>(&FillLayer::setFillOutlineColor);
+ result["fill-outline-color-transition"] = makeTransitionSetter<V>(&FillLayer::setFillOutlineColorTransition);
result["fill-translate"] = makePropertySetter<V>(&FillLayer::setFillTranslate);
+ result["fill-translate-transition"] = makeTransitionSetter<V>(&FillLayer::setFillTranslateTransition);
result["fill-translate-anchor"] = makePropertySetter<V>(&FillLayer::setFillTranslateAnchor);
+ result["fill-translate-anchor-transition"] = makeTransitionSetter<V>(&FillLayer::setFillTranslateAnchorTransition);
result["fill-pattern"] = makePropertySetter<V>(&FillLayer::setFillPattern);
+ result["fill-pattern-transition"] = makeTransitionSetter<V>(&FillLayer::setFillPatternTransition);
result["line-opacity"] = makePropertySetter<V>(&LineLayer::setLineOpacity);
+ result["line-opacity-transition"] = makeTransitionSetter<V>(&LineLayer::setLineOpacityTransition);
result["line-color"] = makePropertySetter<V>(&LineLayer::setLineColor);
+ result["line-color-transition"] = makeTransitionSetter<V>(&LineLayer::setLineColorTransition);
result["line-translate"] = makePropertySetter<V>(&LineLayer::setLineTranslate);
+ result["line-translate-transition"] = makeTransitionSetter<V>(&LineLayer::setLineTranslateTransition);
result["line-translate-anchor"] = makePropertySetter<V>(&LineLayer::setLineTranslateAnchor);
+ result["line-translate-anchor-transition"] = makeTransitionSetter<V>(&LineLayer::setLineTranslateAnchorTransition);
result["line-width"] = makePropertySetter<V>(&LineLayer::setLineWidth);
+ result["line-width-transition"] = makeTransitionSetter<V>(&LineLayer::setLineWidthTransition);
result["line-gap-width"] = makePropertySetter<V>(&LineLayer::setLineGapWidth);
+ result["line-gap-width-transition"] = makeTransitionSetter<V>(&LineLayer::setLineGapWidthTransition);
result["line-offset"] = makePropertySetter<V>(&LineLayer::setLineOffset);
+ result["line-offset-transition"] = makeTransitionSetter<V>(&LineLayer::setLineOffsetTransition);
result["line-blur"] = makePropertySetter<V>(&LineLayer::setLineBlur);
+ result["line-blur-transition"] = makeTransitionSetter<V>(&LineLayer::setLineBlurTransition);
result["line-dasharray"] = makePropertySetter<V>(&LineLayer::setLineDasharray);
+ result["line-dasharray-transition"] = makeTransitionSetter<V>(&LineLayer::setLineDasharrayTransition);
result["line-pattern"] = makePropertySetter<V>(&LineLayer::setLinePattern);
+ result["line-pattern-transition"] = makeTransitionSetter<V>(&LineLayer::setLinePatternTransition);
result["icon-opacity"] = makePropertySetter<V>(&SymbolLayer::setIconOpacity);
+ result["icon-opacity-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconOpacityTransition);
result["icon-color"] = makePropertySetter<V>(&SymbolLayer::setIconColor);
+ result["icon-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconColorTransition);
result["icon-halo-color"] = makePropertySetter<V>(&SymbolLayer::setIconHaloColor);
+ result["icon-halo-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloColorTransition);
result["icon-halo-width"] = makePropertySetter<V>(&SymbolLayer::setIconHaloWidth);
+ result["icon-halo-width-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloWidthTransition);
result["icon-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setIconHaloBlur);
+ result["icon-halo-blur-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconHaloBlurTransition);
result["icon-translate"] = makePropertySetter<V>(&SymbolLayer::setIconTranslate);
+ result["icon-translate-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconTranslateTransition);
result["icon-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setIconTranslateAnchor);
+ result["icon-translate-anchor-transition"] = makeTransitionSetter<V>(&SymbolLayer::setIconTranslateAnchorTransition);
result["text-opacity"] = makePropertySetter<V>(&SymbolLayer::setTextOpacity);
+ result["text-opacity-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextOpacityTransition);
result["text-color"] = makePropertySetter<V>(&SymbolLayer::setTextColor);
+ result["text-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextColorTransition);
result["text-halo-color"] = makePropertySetter<V>(&SymbolLayer::setTextHaloColor);
+ result["text-halo-color-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloColorTransition);
result["text-halo-width"] = makePropertySetter<V>(&SymbolLayer::setTextHaloWidth);
+ result["text-halo-width-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloWidthTransition);
result["text-halo-blur"] = makePropertySetter<V>(&SymbolLayer::setTextHaloBlur);
+ result["text-halo-blur-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextHaloBlurTransition);
result["text-translate"] = makePropertySetter<V>(&SymbolLayer::setTextTranslate);
+ result["text-translate-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextTranslateTransition);
result["text-translate-anchor"] = makePropertySetter<V>(&SymbolLayer::setTextTranslateAnchor);
+ result["text-translate-anchor-transition"] = makeTransitionSetter<V>(&SymbolLayer::setTextTranslateAnchorTransition);
result["circle-radius"] = makePropertySetter<V>(&CircleLayer::setCircleRadius);
+ result["circle-radius-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleRadiusTransition);
result["circle-color"] = makePropertySetter<V>(&CircleLayer::setCircleColor);
+ result["circle-color-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleColorTransition);
result["circle-blur"] = makePropertySetter<V>(&CircleLayer::setCircleBlur);
+ result["circle-blur-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleBlurTransition);
result["circle-opacity"] = makePropertySetter<V>(&CircleLayer::setCircleOpacity);
+ result["circle-opacity-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleOpacityTransition);
result["circle-translate"] = makePropertySetter<V>(&CircleLayer::setCircleTranslate);
+ result["circle-translate-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleTranslateTransition);
result["circle-translate-anchor"] = makePropertySetter<V>(&CircleLayer::setCircleTranslateAnchor);
+ result["circle-translate-anchor-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleTranslateAnchorTransition);
result["circle-pitch-scale"] = makePropertySetter<V>(&CircleLayer::setCirclePitchScale);
+ result["circle-pitch-scale-transition"] = makeTransitionSetter<V>(&CircleLayer::setCirclePitchScaleTransition);
result["circle-stroke-width"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeWidth);
+ result["circle-stroke-width-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeWidthTransition);
result["circle-stroke-color"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeColor);
+ result["circle-stroke-color-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeColorTransition);
result["circle-stroke-opacity"] = makePropertySetter<V>(&CircleLayer::setCircleStrokeOpacity);
+ result["circle-stroke-opacity-transition"] = makeTransitionSetter<V>(&CircleLayer::setCircleStrokeOpacityTransition);
result["fill-extrusion-opacity"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionOpacity);
+ result["fill-extrusion-opacity-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionOpacityTransition);
result["fill-extrusion-color"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionColor);
+ result["fill-extrusion-color-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionColorTransition);
result["fill-extrusion-translate"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionTranslate);
+ result["fill-extrusion-translate-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateTransition);
result["fill-extrusion-translate-anchor"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateAnchor);
+ result["fill-extrusion-translate-anchor-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition);
result["fill-extrusion-pattern"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionPattern);
+ result["fill-extrusion-pattern-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionPatternTransition);
result["fill-extrusion-height"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionHeight);
+ result["fill-extrusion-height-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionHeightTransition);
result["fill-extrusion-base"] = makePropertySetter<V>(&FillExtrusionLayer::setFillExtrusionBase);
+ result["fill-extrusion-base-transition"] = makeTransitionSetter<V>(&FillExtrusionLayer::setFillExtrusionBaseTransition);
result["raster-opacity"] = makePropertySetter<V>(&RasterLayer::setRasterOpacity);
+ result["raster-opacity-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterOpacityTransition);
result["raster-hue-rotate"] = makePropertySetter<V>(&RasterLayer::setRasterHueRotate);
+ result["raster-hue-rotate-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterHueRotateTransition);
result["raster-brightness-min"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMin);
+ result["raster-brightness-min-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterBrightnessMinTransition);
result["raster-brightness-max"] = makePropertySetter<V>(&RasterLayer::setRasterBrightnessMax);
+ result["raster-brightness-max-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterBrightnessMaxTransition);
result["raster-saturation"] = makePropertySetter<V>(&RasterLayer::setRasterSaturation);
+ result["raster-saturation-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterSaturationTransition);
result["raster-contrast"] = makePropertySetter<V>(&RasterLayer::setRasterContrast);
+ result["raster-contrast-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterContrastTransition);
result["raster-fade-duration"] = makePropertySetter<V>(&RasterLayer::setRasterFadeDuration);
+ result["raster-fade-duration-transition"] = makeTransitionSetter<V>(&RasterLayer::setRasterFadeDurationTransition);
result["background-color"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundColor);
+ result["background-color-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundColorTransition);
result["background-pattern"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundPattern);
+ result["background-pattern-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundPatternTransition);
result["background-opacity"] = makePropertySetter<V>(&BackgroundLayer::setBackgroundOpacity);
+ result["background-opacity-transition"] = makeTransitionSetter<V>(&BackgroundLayer::setBackgroundOpacityTransition);
return result;
}
diff --git a/include/mbgl/style/conversion/make_property_setters.hpp.ejs b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
index ed8f6e891c..65fbdea63e 100644
--- a/include/mbgl/style/conversion/make_property_setters.hpp.ejs
+++ b/include/mbgl/style/conversion/make_property_setters.hpp.ejs
@@ -36,6 +36,7 @@ auto makePaintPropertySetters() {
<% for (const layer of locals.layers) { -%>
<% for (const property of layer.paintProperties) { -%>
result["<%- property.name %>"] = makePropertySetter<V>(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>);
+ result["<%- property.name %>-transition"] = makeTransitionSetter<V>(&<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>Transition);
<% } -%>
<% } -%>
diff --git a/include/mbgl/style/conversion/property_setter.hpp b/include/mbgl/style/conversion/property_setter.hpp
index 1a601c7c1b..6a15c64026 100644
--- a/include/mbgl/style/conversion/property_setter.hpp
+++ b/include/mbgl/style/conversion/property_setter.hpp
@@ -4,6 +4,8 @@
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/constant.hpp>
#include <mbgl/style/conversion/property_value.hpp>
+#include <mbgl/style/conversion/data_driven_property_value.hpp>
+#include <mbgl/style/conversion/transition_options.hpp>
#include <functional>
#include <string>
@@ -18,15 +20,15 @@ using LayoutPropertySetter = std::function<optional<Error> (Layer&, const V&)>;
template <class V>
using PaintPropertySetter = std::function<optional<Error> (Layer&, const V&, const optional<std::string>&)>;
-template <class V, class L, class T, class...Args>
-auto makePropertySetter(void (L::*setter)(PropertyValue<T>, const Args&...args)) {
+template <class V, class L, class PropertyValue, class...Args>
+auto makePropertySetter(void (L::*setter)(PropertyValue, const Args&...args)) {
return [setter] (Layer& layer, const V& value, const Args&...args) -> optional<Error> {
L* typedLayer = layer.as<L>();
if (!typedLayer) {
return Error { "layer doesn't support this property" };
}
- Result<PropertyValue<T>> typedValue = convert<PropertyValue<T>>(value);
+ Result<PropertyValue> typedValue = convert<PropertyValue>(value);
if (!typedValue) {
return typedValue.error();
}
@@ -36,6 +38,24 @@ auto makePropertySetter(void (L::*setter)(PropertyValue<T>, const Args&...args))
};
}
+template <class V, class L, class...Args>
+auto makeTransitionSetter(void (L::*setter)(const TransitionOptions&, const Args&...args)) {
+ return [setter] (Layer& layer, const V& value, const Args&...args) -> optional<Error> {
+ L* typedLayer = layer.as<L>();
+ if (!typedLayer) {
+ return Error { "layer doesn't support this property" };
+ }
+
+ Result<TransitionOptions> transition = convert<TransitionOptions>(value);
+ if (!transition) {
+ return transition.error();
+ }
+
+ (typedLayer->*setter)(*transition, args...);
+ return {};
+ };
+}
+
template <class V>
optional<Error> setVisibility(Layer& layer, const V& value) {
if (isUndefined(value)) {
diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp
index de95b56155..d5e2a5c3c8 100644
--- a/include/mbgl/style/conversion/property_value.hpp
+++ b/include/mbgl/style/conversion/property_value.hpp
@@ -16,7 +16,7 @@ struct Converter<PropertyValue<T>> {
if (isUndefined(value)) {
return {};
} else if (isObject(value)) {
- Result<Function<T>> function = convert<Function<T>>(value);
+ Result<CameraFunction<T>> function = convert<CameraFunction<T>>(value);
if (!function) {
return function.error();
}
diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp
new file mode 100644
index 0000000000..cdd65cfe9f
--- /dev/null
+++ b/include/mbgl/style/conversion/transition_options.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/conversion.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+struct Converter<TransitionOptions> {
+public:
+ template <class V>
+ Result<TransitionOptions> operator()(const V& value) const {
+ if (!isObject(value)) {
+ return Error { "transition must be an object" };
+ }
+
+ TransitionOptions result;
+
+ auto duration = objectMember(value, "duration");
+ if (duration) {
+ auto number = toNumber(*duration);
+ if (!number) {
+ return Error { "duration must be a number" };
+ }
+ result.duration = { std::chrono::milliseconds(int64_t(*number)) };
+ }
+
+ auto delay = objectMember(value, "delay");
+ if (delay) {
+ auto number = toNumber(*delay);
+ if (!number) {
+ return Error { "delay must be a number" };
+ }
+ result.delay = { std::chrono::milliseconds(int64_t(*number)) };
+ }
+
+ return result;
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/data_driven_property_value.hpp b/include/mbgl/style/data_driven_property_value.hpp
new file mode 100644
index 0000000000..3f9ac69436
--- /dev/null
+++ b/include/mbgl/style/data_driven_property_value.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <mbgl/util/variant.hpp>
+#include <mbgl/style/undefined.hpp>
+#include <mbgl/style/function/camera_function.hpp>
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class DataDrivenPropertyValue {
+private:
+ using Value = variant<
+ Undefined,
+ T,
+ CameraFunction<T>,
+ SourceFunction<T>,
+ CompositeFunction<T>>;
+
+ Value value;
+
+ friend bool operator==(const DataDrivenPropertyValue& lhs,
+ const DataDrivenPropertyValue& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+ friend bool operator!=(const DataDrivenPropertyValue& lhs,
+ const DataDrivenPropertyValue& rhs) {
+ return !(lhs == rhs);
+ }
+
+public:
+ DataDrivenPropertyValue() = default;
+ DataDrivenPropertyValue( T v) : value(std::move(v)) {}
+ DataDrivenPropertyValue( CameraFunction<T> v) : value(std::move(v)) {}
+ DataDrivenPropertyValue( SourceFunction<T> v) : value(std::move(v)) {}
+ DataDrivenPropertyValue(CompositeFunction<T> v) : value(std::move(v)) {}
+
+ bool isUndefined() const {
+ return value.template is<Undefined>();
+ }
+
+ bool isDataDriven() const {
+ return value.template is<SourceFunction<T>>() || value.template is<CompositeFunction<T>>();
+ }
+
+ template <typename Evaluator>
+ auto evaluate(const Evaluator& evaluator) const {
+ return Value::visit(value, evaluator);
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/filter.hpp b/include/mbgl/style/filter.hpp
index e5d8081d82..5e61adf064 100644
--- a/include/mbgl/style/filter.hpp
+++ b/include/mbgl/style/filter.hpp
@@ -145,6 +145,95 @@ public:
}
};
+
+class TypeEqualsFilter {
+public:
+ FeatureType value;
+
+ friend bool operator==(const TypeEqualsFilter& lhs, const TypeEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class TypeNotEqualsFilter {
+public:
+ FeatureType value;
+
+ friend bool operator==(const TypeNotEqualsFilter& lhs, const TypeNotEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class TypeInFilter {
+public:
+ std::vector<FeatureType> values;
+
+ friend bool operator==(const TypeInFilter& lhs, const TypeInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class TypeNotInFilter {
+public:
+ std::vector<FeatureType> values;
+
+ friend bool operator==(const TypeNotInFilter& lhs, const TypeNotInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+
+class IdentifierEqualsFilter {
+public:
+ FeatureIdentifier value;
+
+ friend bool operator==(const IdentifierEqualsFilter& lhs, const IdentifierEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class IdentifierNotEqualsFilter {
+public:
+ FeatureIdentifier value;
+
+ friend bool operator==(const IdentifierNotEqualsFilter& lhs, const IdentifierNotEqualsFilter& rhs) {
+ return lhs.value == rhs.value;
+ }
+};
+
+class IdentifierInFilter {
+public:
+ std::vector<FeatureIdentifier> values;
+
+ friend bool operator==(const IdentifierInFilter& lhs, const IdentifierInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class IdentifierNotInFilter {
+public:
+ std::vector<FeatureIdentifier> values;
+
+ friend bool operator==(const IdentifierNotInFilter& lhs, const IdentifierNotInFilter& rhs) {
+ return lhs.values == rhs.values;
+ }
+};
+
+class HasIdentifierFilter {
+public:
+ friend bool operator==(const HasIdentifierFilter&, const HasIdentifierFilter&) {
+ return true;
+ }
+};
+
+class NotHasIdentifierFilter {
+public:
+ friend bool operator==(const NotHasIdentifierFilter&, const NotHasIdentifierFilter&) {
+ return true;
+ }
+};
+
+
using FilterBase = variant<
class NullFilter,
class EqualsFilter,
@@ -159,7 +248,17 @@ using FilterBase = variant<
class AllFilter,
class NoneFilter,
class HasFilter,
- class NotHasFilter>;
+ class NotHasFilter,
+ class TypeEqualsFilter,
+ class TypeNotEqualsFilter,
+ class TypeInFilter,
+ class TypeNotInFilter,
+ class IdentifierEqualsFilter,
+ class IdentifierNotEqualsFilter,
+ class IdentifierInFilter,
+ class IdentifierNotInFilter,
+ class HasIdentifierFilter,
+ class NotHasIdentifierFilter>;
class Filter : public FilterBase {
public:
diff --git a/include/mbgl/style/filter_evaluator.hpp b/include/mbgl/style/filter_evaluator.hpp
index 659f554bba..370064445a 100644
--- a/include/mbgl/style/filter_evaluator.hpp
+++ b/include/mbgl/style/filter_evaluator.hpp
@@ -31,37 +31,37 @@ public:
}
bool operator()(const EqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && equal(*actual, filter.value);
}
bool operator()(const NotEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return !actual || !equal(*actual, filter.value);
}
bool operator()(const LessThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ < rhs_; });
}
bool operator()(const LessThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ <= rhs_; });
}
bool operator()(const GreaterThanFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ > rhs_; });
}
bool operator()(const GreaterThanEqualsFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
return actual && compare(*actual, filter.value, [] (const auto& lhs_, const auto& rhs_) { return lhs_ >= rhs_; });
}
bool operator()(const InFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
if (!actual)
return false;
for (const auto& v: filter.values) {
@@ -73,7 +73,7 @@ public:
}
bool operator()(const NotInFilter& filter) const {
- optional<Value> actual = getValue(filter.key);
+ optional<Value> actual = propertyAccessor(filter.key);
if (!actual)
return true;
for (const auto& v: filter.values) {
@@ -112,30 +112,76 @@ public:
}
bool operator()(const HasFilter& filter) const {
- return bool(getValue(filter.key));
+ return bool(propertyAccessor(filter.key));
}
bool operator()(const NotHasFilter& filter) const {
- return !getValue(filter.key);
+ return !propertyAccessor(filter.key);
}
-private:
- optional<Value> getValue(const std::string& key_) const {
- if (key_ == "$type") {
- return optional<Value>(uint64_t(featureType));
- } else if (key_ == "$id") {
- if (featureIdentifier) {
- return FeatureIdentifier::visit(*featureIdentifier, [] (auto id) {
- return Value(std::move(id));
- });
- } else {
- return optional<Value>();
+
+ bool operator()(const TypeEqualsFilter& filter) const {
+ return featureType == filter.value;
+ }
+
+ bool operator()(const TypeNotEqualsFilter& filter) const {
+ return featureType != filter.value;
+ }
+
+ bool operator()(const TypeInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureType == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const TypeNotInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureType == v) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ bool operator()(const IdentifierEqualsFilter& filter) const {
+ return featureIdentifier == filter.value;
+ }
+
+ bool operator()(const IdentifierNotEqualsFilter& filter) const {
+ return featureIdentifier != filter.value;
+ }
+
+ bool operator()(const IdentifierInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureIdentifier == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool operator()(const IdentifierNotInFilter& filter) const {
+ for (const auto& v: filter.values) {
+ if (featureIdentifier == v) {
+ return false;
}
- } else {
- return propertyAccessor(key_);
}
+ return true;
}
+ bool operator()(const HasIdentifierFilter&) const {
+ return bool(featureIdentifier);
+ }
+
+ bool operator()(const NotHasIdentifierFilter&) const {
+ return !featureIdentifier;
+ }
+
+private:
template <class Op>
struct Comparator {
const Op& op;
diff --git a/include/mbgl/style/function.hpp b/include/mbgl/style/function.hpp
deleted file mode 100644
index b023229e4f..0000000000
--- a/include/mbgl/style/function.hpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#pragma once
-
-#include <cassert>
-#include <utility>
-#include <vector>
-
-namespace mbgl {
-namespace style {
-
-template <typename T>
-class Function {
-public:
- using Stop = std::pair<float, T>;
- using Stops = std::vector<Stop>;
-
- Function(Stops stops_, float base_)
- : base(base_), stops(std::move(stops_)) {
- assert(stops.size() > 0);
- }
-
- float getBase() const { return base; }
- const std::vector<std::pair<float, T>>& getStops() const { return stops; }
-
- T evaluate(float z) const;
-
- friend bool operator==(const Function& lhs, const Function& rhs) {
- return lhs.base == rhs.base && lhs.stops == rhs.stops;
- }
-
- friend bool operator!=(const Function& lhs, const Function& rhs) {
- return !(lhs == rhs);
- }
-
-private:
- float base = 1;
- std::vector<std::pair<float, T>> stops;
-};
-
-} // namespace style
-} // namespace mbgl
diff --git a/include/mbgl/style/function/camera_function.hpp b/include/mbgl/style/function/camera_function.hpp
new file mode 100644
index 0000000000..5636b1663c
--- /dev/null
+++ b/include/mbgl/style/function/camera_function.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+#include <mbgl/style/function/interval_stops.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CameraFunction {
+public:
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>>,
+ variant<
+ IntervalStops<T>>>;
+
+ CameraFunction(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ T evaluate(float zoom) const {
+ return stops.match([&] (const auto& s) {
+ return s.evaluate(Value(double(zoom))).value_or(T());
+ });
+ }
+
+ friend bool operator==(const CameraFunction& lhs,
+ const CameraFunction& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+
+ Stops stops;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/categorical_stops.hpp b/include/mbgl/style/function/categorical_stops.hpp
new file mode 100644
index 0000000000..c8505115ab
--- /dev/null
+++ b/include/mbgl/style/function/categorical_stops.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <cassert>
+#include <utility>
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+class CategoricalValue : public variant<bool, int64_t, std::string> {
+public:
+ using variant<bool, int64_t, std::string>::variant;
+};
+
+template <class T>
+class CategoricalStops {
+public:
+ using Stops = std::map<CategoricalValue, T>;
+
+ Stops stops;
+
+ CategoricalStops() = default;
+ CategoricalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ assert(stops.size() > 0);
+ }
+
+ optional<T> evaluate(const Value&) const;
+
+ friend bool operator==(const CategoricalStops& lhs,
+ const CategoricalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_categorical_stops.hpp b/include/mbgl/style/function/composite_categorical_stops.hpp
new file mode 100644
index 0000000000..b796621d1a
--- /dev/null
+++ b/include/mbgl/style/function/composite_categorical_stops.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/style/function/categorical_stops.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeCategoricalStops {
+public:
+ using Stops = std::map<float, std::map<CategoricalValue, T>>;
+ Stops stops;
+
+ CompositeCategoricalStops() = default;
+ CompositeCategoricalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ CategoricalStops<T> innerStops(const std::map<CategoricalValue, T>& stops_) const {
+ return CategoricalStops<T>(stops_);
+ }
+
+ friend bool operator==(const CompositeCategoricalStops& lhs,
+ const CompositeCategoricalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_exponential_stops.hpp b/include/mbgl/style/function/composite_exponential_stops.hpp
new file mode 100644
index 0000000000..f1ad32a04d
--- /dev/null
+++ b/include/mbgl/style/function/composite_exponential_stops.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeExponentialStops {
+public:
+ using Stops = std::map<float, std::map<float, T>>;
+
+ Stops stops;
+ float base = 1.0f;
+
+ CompositeExponentialStops() = default;
+ CompositeExponentialStops(Stops stops_, float base_ = 1.0f)
+ : stops(std::move(stops_)),
+ base(base_) {
+ }
+
+ ExponentialStops<T> innerStops(const std::map<float, T>& stops_) const {
+ return ExponentialStops<T>(stops_, base);
+ }
+
+ friend bool operator==(const CompositeExponentialStops& lhs,
+ const CompositeExponentialStops& rhs) {
+ return lhs.stops == rhs.stops && lhs.base == rhs.base;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_function.hpp b/include/mbgl/style/function/composite_function.hpp
new file mode 100644
index 0000000000..be238fe9c3
--- /dev/null
+++ b/include/mbgl/style/function/composite_function.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include <mbgl/style/function/composite_exponential_stops.hpp>
+#include <mbgl/style/function/composite_interval_stops.hpp>
+#include <mbgl/style/function/composite_categorical_stops.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/range.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <string>
+#include <tuple>
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+namespace style {
+
+// A CompositeFunction consists of an outer zoom function whose stop range values are
+// "inner" source functions. It provides the GL Native implementation of
+// "zoom-and-property" functions from the style spec.
+
+template <class T>
+class CompositeFunction {
+public:
+ using InnerStops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>,
+ CategoricalStops<T>>,
+ variant<
+ IntervalStops<T>,
+ CategoricalStops<T>>>;
+
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ CompositeExponentialStops<T>,
+ CompositeIntervalStops<T>,
+ CompositeCategoricalStops<T>>,
+ variant<
+ CompositeIntervalStops<T>,
+ CompositeCategoricalStops<T>>>;
+
+ CompositeFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
+ : property(std::move(property_)),
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ std::tuple<Range<float>, Range<InnerStops>>
+ coveringRanges(float zoom) const {
+ return stops.match(
+ [&] (const auto& s) {
+ assert(!s.stops.empty());
+ auto minIt = s.stops.lower_bound(zoom);
+ auto maxIt = s.stops.upper_bound(zoom);
+ if (minIt != s.stops.begin()) {
+ minIt--;
+ }
+ return std::make_tuple(
+ Range<float> {
+ minIt == s.stops.end() ? s.stops.rbegin()->first : minIt->first,
+ maxIt == s.stops.end() ? s.stops.rbegin()->first : maxIt->first
+ },
+ Range<InnerStops> {
+ s.innerStops(minIt == s.stops.end() ? s.stops.rbegin()->second : minIt->second),
+ s.innerStops(maxIt == s.stops.end() ? s.stops.rbegin()->second : maxIt->second)
+ }
+ );
+ }
+ );
+ }
+
+ Range<T> evaluate(Range<InnerStops> coveringStops,
+ const GeometryTileFeature& feature,
+ T finalDefaultValue) const {
+ optional<Value> v = feature.getValue(property);
+ if (!v) {
+ return {
+ defaultValue.value_or(finalDefaultValue),
+ defaultValue.value_or(finalDefaultValue)
+ };
+ }
+ auto eval = [&] (const auto& s) {
+ return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue));
+ };
+ return Range<T> {
+ coveringStops.min.match(eval),
+ coveringStops.max.match(eval)
+ };
+ }
+
+ T evaluate(float zoom, const GeometryTileFeature& feature, T finalDefaultValue) const {
+ std::tuple<Range<float>, Range<InnerStops>> ranges = coveringRanges(zoom);
+ Range<T> resultRange = evaluate(std::get<1>(ranges), feature, finalDefaultValue);
+ return util::interpolate(
+ resultRange.min,
+ resultRange.max,
+ util::interpolationFactor(1.0f, std::get<0>(ranges), zoom));
+ }
+
+ friend bool operator==(const CompositeFunction& lhs,
+ const CompositeFunction& rhs) {
+ return std::tie(lhs.property, lhs.stops, lhs.defaultValue)
+ == std::tie(rhs.property, rhs.stops, rhs.defaultValue);
+ }
+
+ std::string property;
+ Stops stops;
+ optional<T> defaultValue;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/composite_interval_stops.hpp b/include/mbgl/style/function/composite_interval_stops.hpp
new file mode 100644
index 0000000000..3c495f2a7f
--- /dev/null
+++ b/include/mbgl/style/function/composite_interval_stops.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <mbgl/style/function/interval_stops.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class CompositeIntervalStops {
+public:
+ using Stops = std::map<float, std::map<float, T>>;
+ Stops stops;
+
+ CompositeIntervalStops() = default;
+ CompositeIntervalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ IntervalStops<T> innerStops(const std::map<float, T>& stops_) const {
+ return IntervalStops<T>(stops_);
+ }
+
+ friend bool operator==(const CompositeIntervalStops& lhs,
+ const CompositeIntervalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/exponential_stops.hpp b/include/mbgl/style/function/exponential_stops.hpp
new file mode 100644
index 0000000000..051f5aa9aa
--- /dev/null
+++ b/include/mbgl/style/function/exponential_stops.hpp
@@ -0,0 +1,54 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/interpolate.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class ExponentialStops {
+public:
+ using Stops = std::map<float, T>;
+
+ Stops stops;
+ float base = 1.0f;
+
+ ExponentialStops() = default;
+ ExponentialStops(Stops stops_, float base_ = 1.0f)
+ : stops(std::move(stops_)),
+ base(base_) {
+ }
+
+ optional<T> evaluate(const Value& value) const {
+ if (stops.empty()) {
+ assert(false);
+ return T();
+ }
+
+ optional<float> z = numericValue<float>(value);
+ if (!z) {
+ return T();
+ }
+
+ auto it = stops.upper_bound(*z);
+ if (it == stops.end()) {
+ return stops.rbegin()->second;
+ } else if (it == stops.begin()) {
+ return stops.begin()->second;
+ } else {
+ return util::interpolate(std::prev(it)->second, it->second,
+ util::interpolationFactor(base, { std::prev(it)->first, it->first }, *z));
+ }
+ }
+
+ friend bool operator==(const ExponentialStops& lhs,
+ const ExponentialStops& rhs) {
+ return lhs.stops == rhs.stops && lhs.base == rhs.base;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/identity_stops.hpp b/include/mbgl/style/function/identity_stops.hpp
new file mode 100644
index 0000000000..741ebbbe0c
--- /dev/null
+++ b/include/mbgl/style/function/identity_stops.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class IdentityStops {
+public:
+ optional<T> evaluate(const Value&) const;
+
+ friend bool operator==(const IdentityStops&,
+ const IdentityStops&) {
+ return true;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/interval_stops.hpp b/include/mbgl/style/function/interval_stops.hpp
new file mode 100644
index 0000000000..50f2b48453
--- /dev/null
+++ b/include/mbgl/style/function/interval_stops.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <mbgl/util/feature.hpp>
+
+#include <map>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class IntervalStops {
+public:
+ using Stops = std::map<float, T>;
+ Stops stops;
+
+ IntervalStops() = default;
+ IntervalStops(Stops stops_)
+ : stops(std::move(stops_)) {
+ }
+
+ optional<T> evaluate(const Value& value) const {
+ if (stops.empty()) {
+ assert(false);
+ return {};
+ }
+
+ optional<float> z = numericValue<float>(value);
+ if (!z) {
+ return {};
+ }
+
+ auto it = stops.upper_bound(*z);
+ if (it == stops.end()) {
+ return stops.rbegin()->second;
+ } else if (it == stops.begin()) {
+ return stops.begin()->second;
+ } else {
+ return std::prev(it)->second;
+ }
+ }
+
+ friend bool operator==(const IntervalStops& lhs,
+ const IntervalStops& rhs) {
+ return lhs.stops == rhs.stops;
+ }
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/function/source_function.hpp b/include/mbgl/style/function/source_function.hpp
new file mode 100644
index 0000000000..29b1067a19
--- /dev/null
+++ b/include/mbgl/style/function/source_function.hpp
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <mbgl/style/function/exponential_stops.hpp>
+#include <mbgl/style/function/interval_stops.hpp>
+#include <mbgl/style/function/categorical_stops.hpp>
+#include <mbgl/style/function/identity_stops.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+#include <string>
+
+namespace mbgl {
+namespace style {
+
+template <class T>
+class SourceFunction {
+public:
+ using Stops = std::conditional_t<
+ util::Interpolatable<T>,
+ variant<
+ ExponentialStops<T>,
+ IntervalStops<T>,
+ CategoricalStops<T>,
+ IdentityStops<T>>,
+ variant<
+ IntervalStops<T>,
+ CategoricalStops<T>,
+ IdentityStops<T>>>;
+
+ SourceFunction(std::string property_, Stops stops_, optional<T> defaultValue_ = {})
+ : property(std::move(property_)),
+ stops(std::move(stops_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ T evaluate(const GeometryTileFeature& feature, T finalDefaultValue) const {
+ optional<Value> v = feature.getValue(property);
+ if (!v) {
+ return defaultValue.value_or(finalDefaultValue);
+ }
+ return stops.match([&] (const auto& s) -> T {
+ return s.evaluate(*v).value_or(defaultValue.value_or(finalDefaultValue));
+ });
+ }
+
+ friend bool operator==(const SourceFunction& lhs,
+ const SourceFunction& rhs) {
+ return std::tie(lhs.property, lhs.stops, lhs.defaultValue)
+ == std::tie(rhs.property, rhs.stops, rhs.defaultValue);
+ }
+
+ std::string property;
+ Stops stops;
+ optional<T> defaultValue;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp
index c120b7f493..94076931e7 100644
--- a/include/mbgl/style/layers/background_layer.hpp
+++ b/include/mbgl/style/layers/background_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class BackgroundLayer : public Layer {
public:
BackgroundLayer(const std::string& layerID);
@@ -21,14 +24,17 @@ public:
static PropertyValue<Color> getDefaultBackgroundColor();
PropertyValue<Color> getBackgroundColor(const optional<std::string>& klass = {}) const;
void setBackgroundColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ void setBackgroundColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultBackgroundPattern();
PropertyValue<std::string> getBackgroundPattern(const optional<std::string>& klass = {}) const;
void setBackgroundPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setBackgroundPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultBackgroundOpacity();
PropertyValue<float> getBackgroundOpacity(const optional<std::string>& klass = {}) const;
void setBackgroundOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setBackgroundOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp
index 5562126c2f..35db4b3962 100644
--- a/include/mbgl/style/layers/circle_layer.hpp
+++ b/include/mbgl/style/layers/circle_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class CircleLayer : public Layer {
public:
CircleLayer(const std::string& layerID, const std::string& sourceID);
@@ -26,45 +29,55 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultCircleRadius();
- PropertyValue<float> getCircleRadius(const optional<std::string>& klass = {}) const;
- void setCircleRadius(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleRadius();
+ DataDrivenPropertyValue<float> getCircleRadius(const optional<std::string>& klass = {}) const;
+ void setCircleRadius(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleRadiusTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultCircleColor();
- PropertyValue<Color> getCircleColor(const optional<std::string>& klass = {}) const;
- void setCircleColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultCircleColor();
+ DataDrivenPropertyValue<Color> getCircleColor(const optional<std::string>& klass = {}) const;
+ void setCircleColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setCircleColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultCircleBlur();
- PropertyValue<float> getCircleBlur(const optional<std::string>& klass = {}) const;
- void setCircleBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleBlur();
+ DataDrivenPropertyValue<float> getCircleBlur(const optional<std::string>& klass = {}) const;
+ void setCircleBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultCircleOpacity();
- PropertyValue<float> getCircleOpacity(const optional<std::string>& klass = {}) const;
- void setCircleOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultCircleOpacity();
+ DataDrivenPropertyValue<float> getCircleOpacity(const optional<std::string>& klass = {}) const;
+ void setCircleOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultCircleTranslate();
PropertyValue<std::array<float, 2>> getCircleTranslate(const optional<std::string>& klass = {}) const;
void setCircleTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setCircleTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultCircleTranslateAnchor();
PropertyValue<TranslateAnchorType> getCircleTranslateAnchor(const optional<std::string>& klass = {}) const;
void setCircleTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setCircleTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<CirclePitchScaleType> getDefaultCirclePitchScale();
PropertyValue<CirclePitchScaleType> getCirclePitchScale(const optional<std::string>& klass = {}) const;
void setCirclePitchScale(PropertyValue<CirclePitchScaleType>, const optional<std::string>& klass = {});
-
- static PropertyValue<float> getDefaultCircleStrokeWidth();
- PropertyValue<float> getCircleStrokeWidth(const optional<std::string>& klass = {}) const;
- void setCircleStrokeWidth(PropertyValue<float>, const optional<std::string>& klass = {});
-
- static PropertyValue<Color> getDefaultCircleStrokeColor();
- PropertyValue<Color> getCircleStrokeColor(const optional<std::string>& klass = {}) const;
- void setCircleStrokeColor(PropertyValue<Color>, const optional<std::string>& klass = {});
-
- static PropertyValue<float> getDefaultCircleStrokeOpacity();
- PropertyValue<float> getCircleStrokeOpacity(const optional<std::string>& klass = {}) const;
- void setCircleStrokeOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setCirclePitchScaleTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<float> getDefaultCircleStrokeWidth();
+ DataDrivenPropertyValue<float> getCircleStrokeWidth(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleStrokeWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<Color> getDefaultCircleStrokeColor();
+ DataDrivenPropertyValue<Color> getCircleStrokeColor(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setCircleStrokeColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
+
+ static DataDrivenPropertyValue<float> getDefaultCircleStrokeOpacity();
+ DataDrivenPropertyValue<float> getCircleStrokeOpacity(const optional<std::string>& klass = {}) const;
+ void setCircleStrokeOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setCircleStrokeOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp
index 08728af309..c19a4ee168 100644
--- a/include/mbgl/style/layers/fill_extrusion_layer.hpp
+++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class FillExtrusionLayer : public Layer {
public:
FillExtrusionLayer(const std::string& layerID, const std::string& sourceID);
@@ -29,30 +32,37 @@ public:
static PropertyValue<float> getDefaultFillExtrusionOpacity();
PropertyValue<float> getFillExtrusionOpacity(const optional<std::string>& klass = {}) const;
void setFillExtrusionOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillExtrusionColor();
- PropertyValue<Color> getFillExtrusionColor(const optional<std::string>& klass = {}) const;
- void setFillExtrusionColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillExtrusionColor();
+ DataDrivenPropertyValue<Color> getFillExtrusionColor(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillExtrusionColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultFillExtrusionTranslate();
PropertyValue<std::array<float, 2>> getFillExtrusionTranslate(const optional<std::string>& klass = {}) const;
void setFillExtrusionTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setFillExtrusionTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultFillExtrusionTranslateAnchor();
PropertyValue<TranslateAnchorType> getFillExtrusionTranslateAnchor(const optional<std::string>& klass = {}) const;
void setFillExtrusionTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setFillExtrusionTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultFillExtrusionPattern();
PropertyValue<std::string> getFillExtrusionPattern(const optional<std::string>& klass = {}) const;
void setFillExtrusionPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setFillExtrusionPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillExtrusionHeight();
- PropertyValue<float> getFillExtrusionHeight(const optional<std::string>& klass = {}) const;
- void setFillExtrusionHeight(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillExtrusionHeight();
+ DataDrivenPropertyValue<float> getFillExtrusionHeight(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionHeight(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionHeightTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillExtrusionBase();
- PropertyValue<float> getFillExtrusionBase(const optional<std::string>& klass = {}) const;
- void setFillExtrusionBase(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillExtrusionBase();
+ DataDrivenPropertyValue<float> getFillExtrusionBase(const optional<std::string>& klass = {}) const;
+ void setFillExtrusionBase(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillExtrusionBaseTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp
index 4b9201641d..c064eab350 100644
--- a/include/mbgl/style/layers/fill_layer.hpp
+++ b/include/mbgl/style/layers/fill_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class FillLayer : public Layer {
public:
FillLayer(const std::string& layerID, const std::string& sourceID);
@@ -29,30 +32,37 @@ public:
static PropertyValue<bool> getDefaultFillAntialias();
PropertyValue<bool> getFillAntialias(const optional<std::string>& klass = {}) const;
void setFillAntialias(PropertyValue<bool>, const optional<std::string>& klass = {});
+ void setFillAntialiasTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultFillOpacity();
- PropertyValue<float> getFillOpacity(const optional<std::string>& klass = {}) const;
- void setFillOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultFillOpacity();
+ DataDrivenPropertyValue<float> getFillOpacity(const optional<std::string>& klass = {}) const;
+ void setFillOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setFillOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillColor();
- PropertyValue<Color> getFillColor(const optional<std::string>& klass = {}) const;
- void setFillColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillColor();
+ DataDrivenPropertyValue<Color> getFillColor(const optional<std::string>& klass = {}) const;
+ void setFillColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultFillOutlineColor();
- PropertyValue<Color> getFillOutlineColor(const optional<std::string>& klass = {}) const;
- void setFillOutlineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultFillOutlineColor();
+ DataDrivenPropertyValue<Color> getFillOutlineColor(const optional<std::string>& klass = {}) const;
+ void setFillOutlineColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setFillOutlineColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultFillTranslate();
PropertyValue<std::array<float, 2>> getFillTranslate(const optional<std::string>& klass = {}) const;
void setFillTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setFillTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultFillTranslateAnchor();
PropertyValue<TranslateAnchorType> getFillTranslateAnchor(const optional<std::string>& klass = {}) const;
void setFillTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setFillTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultFillPattern();
PropertyValue<std::string> getFillPattern(const optional<std::string>& klass = {}) const;
void setFillPattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setFillPatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs
index 15d0fcee61..d66eae8198 100644
--- a/include/mbgl/style/layers/layer.hpp.ejs
+++ b/include/mbgl/style/layers/layer.hpp.ejs
@@ -10,6 +10,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -20,6 +21,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class <%- camelize(type) %>Layer : public Layer {
public:
<% if (type === 'background') { -%>
@@ -45,18 +48,19 @@ public:
// Layout properties
<% for (const property of layoutProperties) { -%>
- static PropertyValue<<%- propertyType(property) %>> getDefault<%- camelize(property.name) %>();
- PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() const;
- void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>);
+ static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>();
+ <%- propertyValueType(property) %> get<%- camelize(property.name) %>() const;
+ void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>);
<% } -%>
<% } -%>
// Paint properties
<% for (const property of paintProperties) { -%>
- static PropertyValue<<%- propertyType(property) %>> getDefault<%- camelize(property.name) %>();
- PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>(const optional<std::string>& klass = {}) const;
- void set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>>, const optional<std::string>& klass = {});
+ static <%- propertyValueType(property) %> getDefault<%- camelize(property.name) %>();
+ <%- propertyValueType(property) %> get<%- camelize(property.name) %>(const optional<std::string>& klass = {}) const;
+ void set<%- camelize(property.name) %>(<%- propertyValueType(property) %>, const optional<std::string>& klass = {});
+ void set<%- camelize(property.name) %>Transition(const TransitionOptions&, const optional<std::string>& klass = {});
<% } -%>
// Private implementation
diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp
index c3c1026bcd..2ed269ae74 100644
--- a/include/mbgl/style/layers/line_layer.hpp
+++ b/include/mbgl/style/layers/line_layer.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -13,6 +14,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class LineLayer : public Layer {
public:
LineLayer(const std::string& layerID, const std::string& sourceID);
@@ -46,45 +49,55 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultLineOpacity();
- PropertyValue<float> getLineOpacity(const optional<std::string>& klass = {}) const;
- void setLineOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineOpacity();
+ DataDrivenPropertyValue<float> getLineOpacity(const optional<std::string>& klass = {}) const;
+ void setLineOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultLineColor();
- PropertyValue<Color> getLineColor(const optional<std::string>& klass = {}) const;
- void setLineColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultLineColor();
+ DataDrivenPropertyValue<Color> getLineColor(const optional<std::string>& klass = {}) const;
+ void setLineColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setLineColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultLineTranslate();
PropertyValue<std::array<float, 2>> getLineTranslate(const optional<std::string>& klass = {}) const;
void setLineTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setLineTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultLineTranslateAnchor();
PropertyValue<TranslateAnchorType> getLineTranslateAnchor(const optional<std::string>& klass = {}) const;
void setLineTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setLineTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultLineWidth();
PropertyValue<float> getLineWidth(const optional<std::string>& klass = {}) const;
void setLineWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineGapWidth();
- PropertyValue<float> getLineGapWidth(const optional<std::string>& klass = {}) const;
- void setLineGapWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineGapWidth();
+ DataDrivenPropertyValue<float> getLineGapWidth(const optional<std::string>& klass = {}) const;
+ void setLineGapWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineGapWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineOffset();
- PropertyValue<float> getLineOffset(const optional<std::string>& klass = {}) const;
- void setLineOffset(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineOffset();
+ DataDrivenPropertyValue<float> getLineOffset(const optional<std::string>& klass = {}) const;
+ void setLineOffset(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineOffsetTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultLineBlur();
- PropertyValue<float> getLineBlur(const optional<std::string>& klass = {}) const;
- void setLineBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultLineBlur();
+ DataDrivenPropertyValue<float> getLineBlur(const optional<std::string>& klass = {}) const;
+ void setLineBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setLineBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::vector<float>> getDefaultLineDasharray();
PropertyValue<std::vector<float>> getLineDasharray(const optional<std::string>& klass = {}) const;
void setLineDasharray(PropertyValue<std::vector<float>>, const optional<std::string>& klass = {});
+ void setLineDasharrayTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::string> getDefaultLinePattern();
PropertyValue<std::string> getLinePattern(const optional<std::string>& klass = {}) const;
void setLinePattern(PropertyValue<std::string>, const optional<std::string>& klass = {});
+ void setLinePatternTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp
index ae6ec7f91c..72665baa72 100644
--- a/include/mbgl/style/layers/raster_layer.hpp
+++ b/include/mbgl/style/layers/raster_layer.hpp
@@ -5,12 +5,15 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class RasterLayer : public Layer {
public:
RasterLayer(const std::string& layerID, const std::string& sourceID);
@@ -24,30 +27,37 @@ public:
static PropertyValue<float> getDefaultRasterOpacity();
PropertyValue<float> getRasterOpacity(const optional<std::string>& klass = {}) const;
void setRasterOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterHueRotate();
PropertyValue<float> getRasterHueRotate(const optional<std::string>& klass = {}) const;
void setRasterHueRotate(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterHueRotateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterBrightnessMin();
PropertyValue<float> getRasterBrightnessMin(const optional<std::string>& klass = {}) const;
void setRasterBrightnessMin(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterBrightnessMinTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterBrightnessMax();
PropertyValue<float> getRasterBrightnessMax(const optional<std::string>& klass = {}) const;
void setRasterBrightnessMax(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterBrightnessMaxTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterSaturation();
PropertyValue<float> getRasterSaturation(const optional<std::string>& klass = {}) const;
void setRasterSaturation(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterSaturationTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterContrast();
PropertyValue<float> getRasterContrast(const optional<std::string>& klass = {}) const;
void setRasterContrast(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterContrastTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<float> getDefaultRasterFadeDuration();
PropertyValue<float> getRasterFadeDuration(const optional<std::string>& klass = {}) const;
void setRasterFadeDuration(PropertyValue<float>, const optional<std::string>& klass = {});
+ void setRasterFadeDurationTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp
index 1e2e6ac454..aeccabb97e 100644
--- a/include/mbgl/style/layers/symbol_layer.hpp
+++ b/include/mbgl/style/layers/symbol_layer.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/style/filter.hpp>
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/util/color.hpp>
@@ -13,6 +14,8 @@
namespace mbgl {
namespace style {
+class TransitionOptions;
+
class SymbolLayer : public Layer {
public:
SymbolLayer(const std::string& layerID, const std::string& sourceID);
@@ -72,9 +75,9 @@ public:
PropertyValue<std::string> getIconImage() const;
void setIconImage(PropertyValue<std::string>);
- static PropertyValue<float> getDefaultIconRotate();
- PropertyValue<float> getIconRotate() const;
- void setIconRotate(PropertyValue<float>);
+ static DataDrivenPropertyValue<float> getDefaultIconRotate();
+ DataDrivenPropertyValue<float> getIconRotate() const;
+ void setIconRotate(DataDrivenPropertyValue<float>);
static PropertyValue<float> getDefaultIconPadding();
PropertyValue<float> getIconPadding() const;
@@ -84,9 +87,9 @@ public:
PropertyValue<bool> getIconKeepUpright() const;
void setIconKeepUpright(PropertyValue<bool>);
- static PropertyValue<std::array<float, 2>> getDefaultIconOffset();
- PropertyValue<std::array<float, 2>> getIconOffset() const;
- void setIconOffset(PropertyValue<std::array<float, 2>>);
+ static DataDrivenPropertyValue<std::array<float, 2>> getDefaultIconOffset();
+ DataDrivenPropertyValue<std::array<float, 2>> getIconOffset() const;
+ void setIconOffset(DataDrivenPropertyValue<std::array<float, 2>>);
static PropertyValue<AlignmentType> getDefaultTextPitchAlignment();
PropertyValue<AlignmentType> getTextPitchAlignment() const;
@@ -96,9 +99,9 @@ public:
PropertyValue<AlignmentType> getTextRotationAlignment() const;
void setTextRotationAlignment(PropertyValue<AlignmentType>);
- static PropertyValue<std::string> getDefaultTextField();
- PropertyValue<std::string> getTextField() const;
- void setTextField(PropertyValue<std::string>);
+ static DataDrivenPropertyValue<std::string> getDefaultTextField();
+ DataDrivenPropertyValue<std::string> getTextField() const;
+ void setTextField(DataDrivenPropertyValue<std::string>);
static PropertyValue<std::vector<std::string>> getDefaultTextFont();
PropertyValue<std::vector<std::string>> getTextFont() const;
@@ -144,9 +147,9 @@ public:
PropertyValue<bool> getTextKeepUpright() const;
void setTextKeepUpright(PropertyValue<bool>);
- static PropertyValue<TextTransformType> getDefaultTextTransform();
- PropertyValue<TextTransformType> getTextTransform() const;
- void setTextTransform(PropertyValue<TextTransformType>);
+ static DataDrivenPropertyValue<TextTransformType> getDefaultTextTransform();
+ DataDrivenPropertyValue<TextTransformType> getTextTransform() const;
+ void setTextTransform(DataDrivenPropertyValue<TextTransformType>);
static PropertyValue<std::array<float, 2>> getDefaultTextOffset();
PropertyValue<std::array<float, 2>> getTextOffset() const;
@@ -166,61 +169,75 @@ public:
// Paint properties
- static PropertyValue<float> getDefaultIconOpacity();
- PropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
- void setIconOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconOpacity();
+ DataDrivenPropertyValue<float> getIconOpacity(const optional<std::string>& klass = {}) const;
+ void setIconOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultIconColor();
- PropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
- void setIconColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultIconColor();
+ DataDrivenPropertyValue<Color> getIconColor(const optional<std::string>& klass = {}) const;
+ void setIconColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setIconColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultIconHaloColor();
- PropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
- void setIconHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultIconHaloColor();
+ DataDrivenPropertyValue<Color> getIconHaloColor(const optional<std::string>& klass = {}) const;
+ void setIconHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setIconHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultIconHaloWidth();
- PropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
- void setIconHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconHaloWidth();
+ DataDrivenPropertyValue<float> getIconHaloWidth(const optional<std::string>& klass = {}) const;
+ void setIconHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultIconHaloBlur();
- PropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
- void setIconHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultIconHaloBlur();
+ DataDrivenPropertyValue<float> getIconHaloBlur(const optional<std::string>& klass = {}) const;
+ void setIconHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setIconHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultIconTranslate();
PropertyValue<std::array<float, 2>> getIconTranslate(const optional<std::string>& klass = {}) const;
void setIconTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setIconTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultIconTranslateAnchor();
PropertyValue<TranslateAnchorType> getIconTranslateAnchor(const optional<std::string>& klass = {}) const;
void setIconTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setIconTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextOpacity();
- PropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
- void setTextOpacity(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextOpacity();
+ DataDrivenPropertyValue<float> getTextOpacity(const optional<std::string>& klass = {}) const;
+ void setTextOpacity(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextOpacityTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultTextColor();
- PropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
- void setTextColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultTextColor();
+ DataDrivenPropertyValue<Color> getTextColor(const optional<std::string>& klass = {}) const;
+ void setTextColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setTextColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<Color> getDefaultTextHaloColor();
- PropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
- void setTextHaloColor(PropertyValue<Color>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<Color> getDefaultTextHaloColor();
+ DataDrivenPropertyValue<Color> getTextHaloColor(const optional<std::string>& klass = {}) const;
+ void setTextHaloColor(DataDrivenPropertyValue<Color>, const optional<std::string>& klass = {});
+ void setTextHaloColorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextHaloWidth();
- PropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
- void setTextHaloWidth(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextHaloWidth();
+ DataDrivenPropertyValue<float> getTextHaloWidth(const optional<std::string>& klass = {}) const;
+ void setTextHaloWidth(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextHaloWidthTransition(const TransitionOptions&, const optional<std::string>& klass = {});
- static PropertyValue<float> getDefaultTextHaloBlur();
- PropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
- void setTextHaloBlur(PropertyValue<float>, const optional<std::string>& klass = {});
+ static DataDrivenPropertyValue<float> getDefaultTextHaloBlur();
+ DataDrivenPropertyValue<float> getTextHaloBlur(const optional<std::string>& klass = {}) const;
+ void setTextHaloBlur(DataDrivenPropertyValue<float>, const optional<std::string>& klass = {});
+ void setTextHaloBlurTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<std::array<float, 2>> getDefaultTextTranslate();
PropertyValue<std::array<float, 2>> getTextTranslate(const optional<std::string>& klass = {}) const;
void setTextTranslate(PropertyValue<std::array<float, 2>>, const optional<std::string>& klass = {});
+ void setTextTranslateTransition(const TransitionOptions&, const optional<std::string>& klass = {});
static PropertyValue<TranslateAnchorType> getDefaultTextTranslateAnchor();
PropertyValue<TranslateAnchorType> getTextTranslateAnchor(const optional<std::string>& klass = {}) const;
void setTextTranslateAnchor(PropertyValue<TranslateAnchorType>, const optional<std::string>& klass = {});
+ void setTextTranslateAnchorTransition(const TransitionOptions&, const optional<std::string>& klass = {});
// Private implementation
diff --git a/include/mbgl/style/property_value.hpp b/include/mbgl/style/property_value.hpp
index 83c4b4cf1b..e784633aa7 100644
--- a/include/mbgl/style/property_value.hpp
+++ b/include/mbgl/style/property_value.hpp
@@ -1,20 +1,16 @@
#pragma once
#include <mbgl/util/variant.hpp>
-#include <mbgl/style/function.hpp>
+#include <mbgl/style/undefined.hpp>
+#include <mbgl/style/function/camera_function.hpp>
namespace mbgl {
namespace style {
-class Undefined {};
-
-inline bool operator==(const Undefined&, const Undefined&) { return true; }
-inline bool operator!=(const Undefined&, const Undefined&) { return false; }
-
template <class T>
class PropertyValue {
private:
- using Value = variant<Undefined, T, Function<T>>;
+ using Value = variant<Undefined, T, CameraFunction<T>>;
Value value;
friend bool operator==(const PropertyValue& lhs, const PropertyValue& rhs) {
@@ -26,16 +22,16 @@ private:
}
public:
- PropertyValue() : value() {}
- PropertyValue( T constant) : value(constant) {}
- PropertyValue(Function<T> function) : value(function) {}
+ PropertyValue() : value() {}
+ PropertyValue( T constant) : value(constant) {}
+ PropertyValue(CameraFunction<T> function) : value(function) {}
- bool isUndefined() const { return value.which() == 0; }
- bool isConstant() const { return value.which() == 1; }
- bool isFunction() const { return value.which() == 2; }
+ bool isUndefined() const { return value.which() == 0; }
+ bool isConstant() const { return value.which() == 1; }
+ bool isCameraFunction() const { return value.which() == 2; }
- const T & asConstant() const { return value.template get< T >(); }
- const Function<T>& asFunction() const { return value.template get<Function<T>>(); }
+ const T & asConstant() const { return value.template get< T >(); }
+ const CameraFunction<T>& asCameraFunction() const { return value.template get<CameraFunction<T>>(); }
explicit operator bool() const { return !isUndefined(); };
diff --git a/include/mbgl/style/undefined.hpp b/include/mbgl/style/undefined.hpp
new file mode 100644
index 0000000000..e43f132a80
--- /dev/null
+++ b/include/mbgl/style/undefined.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+namespace mbgl {
+namespace style {
+
+class Undefined {};
+
+inline bool operator==(const Undefined&, const Undefined&) { return true; }
+inline bool operator!=(const Undefined&, const Undefined&) { return false; }
+
+} // namespace style
+} // namespace mbgl
diff --git a/include/mbgl/util/chrono.hpp b/include/mbgl/util/chrono.hpp
index 4adf030331..723cd131e3 100644
--- a/include/mbgl/util/chrono.hpp
+++ b/include/mbgl/util/chrono.hpp
@@ -29,7 +29,7 @@ std::string rfc1123(Timestamp);
std::string iso8601(Timestamp);
Timestamp parseTimestamp(const char *);
-
+
Timestamp parseTimestamp(const int32_t timestamp);
// C++17 polyfill
diff --git a/include/mbgl/util/compression.hpp b/include/mbgl/util/compression.hpp
index 5e232187c3..93a3ddb8bc 100644
--- a/include/mbgl/util/compression.hpp
+++ b/include/mbgl/util/compression.hpp
@@ -4,9 +4,9 @@
namespace mbgl {
namespace util {
-
+
std::string compress(const std::string& raw);
std::string decompress(const std::string& raw);
-
+
} // namespace util
} // namespace mbgl
diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp
index 85e19c2ff0..0f2779e33b 100644
--- a/include/mbgl/util/constants.hpp
+++ b/include/mbgl/util/constants.hpp
@@ -44,11 +44,11 @@ constexpr Duration DEFAULT_FADE_DURATION = Milliseconds(300);
constexpr Seconds CLOCK_SKEW_RETRY_TIMEOUT { 30 };
constexpr UnitBezier DEFAULT_TRANSITION_EASE = { 0, 0, 0.25, 1 };
-
+
constexpr int DEFAULT_RATE_LIMIT_TIMEOUT = 5;
constexpr const char* API_BASE_URL = "https://api.mapbox.com";
-
+
} // namespace util
namespace debug {
diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp
index b72aa15ddd..4eeceda944 100644
--- a/include/mbgl/util/feature.hpp
+++ b/include/mbgl/util/feature.hpp
@@ -12,4 +12,21 @@ using PropertyMap = mapbox::geometry::property_map;
using FeatureIdentifier = mapbox::geometry::identifier;
using Feature = mapbox::geometry::feature<double>;
+template <class T>
+optional<T> numericValue(const Value& value) {
+ return value.match(
+ [] (uint64_t t) {
+ return optional<T>(t);
+ },
+ [] (int64_t t) {
+ return optional<T>(t);
+ },
+ [] (double t) {
+ return optional<T>(t);
+ },
+ [] (auto) {
+ return optional<T>();
+ });
+}
+
} // namespace mbgl
diff --git a/include/mbgl/util/geo.hpp b/include/mbgl/util/geo.hpp
index 9dca10eb84..57a028e467 100644
--- a/include/mbgl/util/geo.hpp
+++ b/include/mbgl/util/geo.hpp
@@ -187,10 +187,10 @@ enum class NorthOrientation : uint8_t {
/// The distance on each side between a rectangle and a rectangle within.
class EdgeInsets {
public:
- double top = 0; ///< Number of pixels inset from the top edge.
- double left = 0; ///< Number of pixels inset from the left edge.
- double bottom = 0; ///< Number of pixels inset from the bottom edge.
- double right = 0; ///< Number of pixels inset from the right edge.
+ double top = 0; // Number of pixels inset from the top edge.
+ double left = 0; // Number of pixels inset from the left edge.
+ double bottom = 0; // Number of pixels inset from the bottom edge.
+ double right = 0; // Number of pixels inset from the right edge.
EdgeInsets() {}
diff --git a/include/mbgl/util/image.hpp b/include/mbgl/util/image.hpp
index 1d84d4824a..5d1462e7c4 100644
--- a/include/mbgl/util/image.hpp
+++ b/include/mbgl/util/image.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
#include <mbgl/util/size.hpp>
#include <string>
@@ -24,6 +25,15 @@ public:
: size(std::move(size_)),
data(std::make_unique<uint8_t[]>(bytes())) {}
+ Image(Size size_, const uint8_t* srcData, std::size_t srcLength)
+ : size(std::move(size_)) {
+ if (srcLength != bytes()) {
+ throw std::invalid_argument("mismatched image size");
+ }
+ data = std::make_unique<uint8_t[]>(bytes());
+ std::copy(srcData, srcData + srcLength, data.get());
+ }
+
Image(Size size_, std::unique_ptr<uint8_t[]> data_)
: size(std::move(size_)),
data(std::move(data_)) {}
@@ -38,19 +48,73 @@ public:
return *this;
}
- bool operator==(const Image& rhs) const {
- return size == rhs.size &&
- std::equal(data.get(), data.get() + bytes(), rhs.data.get(),
- rhs.data.get() + rhs.bytes());
+ friend bool operator==(const Image& lhs, const Image& rhs) {
+ return std::equal(lhs.data.get(), lhs.data.get() + lhs.bytes(),
+ rhs.data.get(), rhs.data.get() + rhs.bytes());
+ }
+
+ friend bool operator!=(const Image& lhs, const Image& rhs) {
+ return !(lhs == rhs);
}
bool valid() const {
return size && data.get() != nullptr;
}
+ template <typename T = Image>
+ T clone() const {
+ T copy(size);
+ std::copy(data.get(), data.get() + bytes(), copy.data.get());
+ return copy;
+ }
+
size_t stride() const { return channels * size.width; }
size_t bytes() const { return stride() * size.height; }
+ void fill(uint8_t value) {
+ std::fill(data.get(), data.get() + bytes(), value);
+ }
+
+ // Copy image data within `rect` from `src` to the rectangle of the same size at `pt`
+ // in `dst`. If the specified bounds exceed the bounds of the source or destination,
+ // throw `std::out_of_range`. Must not be used to move data within a single Image.
+ static void copy(const Image& srcImg, Image& dstImg, const Point<uint32_t>& srcPt, const Point<uint32_t>& dstPt, const Size& size) {
+ if (!srcImg.valid()) {
+ throw std::invalid_argument("invalid source for image copy");
+ }
+
+ if (!dstImg.valid()) {
+ throw std::invalid_argument("invalid destination for image copy");
+ }
+
+ if (size.width > srcImg.size.width ||
+ size.height > srcImg.size.height ||
+ srcPt.x > srcImg.size.width - size.width ||
+ srcPt.y > srcImg.size.height - size.height) {
+ throw std::out_of_range("out of range source coordinates for image copy");
+ }
+
+ if (size.width > dstImg.size.width ||
+ size.height > dstImg.size.height ||
+ dstPt.x > dstImg.size.width - size.width ||
+ dstPt.y > dstImg.size.height - size.height) {
+ throw std::out_of_range("out of range destination coordinates for image copy");
+ }
+
+ const uint8_t* srcData = srcImg.data.get();
+ uint8_t* dstData = dstImg.data.get();
+
+ assert(srcData != dstData);
+
+ for (uint32_t y = 0; y < size.height; y++) {
+ const std::size_t srcOffset = (srcPt.y + y) * srcImg.stride() + srcPt.x * channels;
+ const std::size_t dstOffset = (dstPt.y + y) * dstImg.stride() + dstPt.x * channels;
+ std::copy(srcData + srcOffset,
+ srcData + srcOffset + size.width * channels,
+ dstData + dstOffset);
+ }
+ }
+
Size size;
static constexpr size_t channels = Mode == ImageAlphaMode::Exclusive ? 1 : 4;
std::unique_ptr<uint8_t[]> data;
diff --git a/include/mbgl/util/size.hpp b/include/mbgl/util/size.hpp
index 1af85bcff5..79679a92fb 100644
--- a/include/mbgl/util/size.hpp
+++ b/include/mbgl/util/size.hpp
@@ -13,6 +13,10 @@ public:
constexpr Size(const uint32_t width_, const uint32_t height_) : width(width_), height(height_) {
}
+ constexpr uint32_t area() const {
+ return width * height;
+ }
+
constexpr explicit operator bool() const {
return width > 0 && height > 0;
}
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject 878008895104b67861ce73f65809f7f6f0ed726
+Subproject 7804faf89741cf7db90582d9e0881253cb9d4cd
diff --git a/package.json b/package.json
index 5a9e159cc5..d389b06514 100644
--- a/package.json
+++ b/package.json
@@ -22,9 +22,6 @@
"ejs": "^2.4.1",
"express": "^4.11.1",
"lodash": "^4.16.4",
- "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#49e8b407bdbbe6f7c92dbcb56d3d51f425fc2653",
- "mkdirp": "^0.5.1",
- "node-cmake": "^1.2.1",
"pixelmatch": "^4.0.2",
"pngjs": "^3.0.0",
"request": "^2.72.0",
@@ -48,4 +45,4 @@
"remote_path": "./{name}/v{version}",
"package_name": "{node_abi}-{platform}-{arch}.tar.gz"
}
-} \ No newline at end of file
+}
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index c702e1e759..1186d392d0 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -2,39 +2,56 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
-## 5.0.0 - TBA
+## 5.0.0-beta.1 - February 14th, 2017
+* Support for data-driven styles [#7752](https://github.com/mapbox/mapbox-gl-native/pull/7752)
* Consistent double tap zoom acceleration [#7514](https://github.com/mapbox/mapbox-gl-native/issues/7514)
-* Cleanup inconsistencies float vs double [#4445](https://github.com/mapbox/mapbox-gl-native/issues/4445)
+* Cleanup inconsistencies `float` vs `double` [#4445](https://github.com/mapbox/mapbox-gl-native/issues/4445)
* Add `mapbox_` prefix to attributes [#6482](https://github.com/mapbox/mapbox-gl-native/issues/6482)
* Update LOST to 2.0.0 [#6573](https://github.com/mapbox/mapbox-gl-native/issues/6537)
+* MAS submodules (geojson, telemetry) are now smaller to reduce the overall method count [#7642](https://github.com/mapbox/mapbox-gl-native/pull/7642)
* Support for Android Nougat [#5910](5910-move-listener-logic-for-nougat)
- - move location listening logic to onStart/onStop Activity lifecylce methods
-* Removal of accesstoken on MapView and MapboxMap [#5621](https://github.com/mapbox/mapbox-gl-native/issues/5621)
+ - Move location listening logic to onStart/onStop Activity lifecylce methods
+* Removal of `accessToken` on `MapView` and `MapboxMap` [#5621](https://github.com/mapbox/mapbox-gl-native/issues/5621)
* Introduction of new make targets [#5940](https://github.com/mapbox/mapbox-gl-native/issues/5940)
- - Targets for testing, running and using external tools directly from the commandline
-* Cleanup gradle files [#6009](https://github.com/mapbox/mapbox-gl-native/issues/6009)
- - Introducing single purpose .gradle files
+ - Targets for testing, running and using external tools directly from the command line
+* Cleanup Gradle files [#6009](https://github.com/mapbox/mapbox-gl-native/issues/6009)
+ - Introducing single purpose `.gradle` files
* Checkstyle integration [#7442](https://github.com/mapbox/mapbox-gl-native/pull/7442)
* Transform refactor [#6532](https://github.com/mapbox/mapbox-gl-native/issues/6532)
- - All camera related code is moved to a dedicated transfrom class cfr. core architecture
+ - All camera related code is moved to a dedicated transform class cfr. core architecture
* Encapsulate Gestures [#6557](https://github.com/mapbox/mapbox-gl-native/issues/6557)
- - All gesture event code is encapsulated in MapGestureDetector
- - All key event code is encapsulated in MapKeyListener
-* Transparent background for MyLocationView [#7116](https://github.com/mapbox/mapbox-gl-native/issues/7116)
+ - All gesture event code is encapsulated in `MapGestureDetector`
+ - All key event code is encapsulated in `MapKeyListener`
+* Transparent background for `MyLocationView` [#7116](https://github.com/mapbox/mapbox-gl-native/issues/7116)
* Update documentation on generate sanity tests [#7147](https://github.com/mapbox/mapbox-gl-native/issues/7147)
* Update documentation on style templates [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157)
-* NullPointerException during save instance state [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157)
+* `NullPointerException` during save instance state [#7157](https://github.com/mapbox/mapbox-gl-native/issues/7157)
* Move management style to core [#7275](https://github.com/mapbox/mapbox-gl-native/issues/7275)
-* OnCameraChange not called for the final position of animation bug [#7350](https://github.com/mapbox/mapbox-gl-native/issues/7350)
-* MapboxAccountManager refactor [#6534](https://github.com/mapbox/mapbox-gl-native/issues/6534)
+* `OnCameraChange` not called for the final position of animation bug [#7350](https://github.com/mapbox/mapbox-gl-native/issues/7350)
+* `MapboxAccountManager` refactor [#6534](https://github.com/mapbox/mapbox-gl-native/issues/6534)
- Consolidating the location where tokens are set
- Rename to reflect the increased responsibilities introduced in prior releases
* AnnotationManager refactor [#6067](https://github.com/mapbox/mapbox-gl-native/issues/6067)
- - Extracting all business logic related to annotations into a seperate class cfr. to core and the iOS codebase
+ - Extracting all business logic related to annotations into a separate class cfr. to core and the iOS codebase
* Gesture handling bugs
- Avoid calls to onFling when while pinch zooming [#7666](https://github.com/mapbox/mapbox-gl-native/issues/7666)
* Support for style-wide transition animation duration and delay [#6779](https://github.com/mapbox/mapbox-gl-native/issues/6779)
+* Support for all animated camera changes to configure dismissing tracking modes [#7854](https://github.com/mapbox/mapbox-gl-native/issues/7854)
+* `LatLng` objects produced by the SDK are wrapped by default for [compatibility](https://developers.google.com/android/reference/com/google/android/gms/maps/model/LatLng) with the Google Maps API on Android [#4522](https://github.com/mapbox/mapbox-gl-native/issues/4522)
+
+## 4.2.2 - January 27, 2017
+
+Mapbox Android 4.2.2 builds further on v4.2.1 and resolves:
+* OnFling gesture improvements
+ - Improve fling by calculating animation time based on velocity [#7676](https://github.com/mapbox/mapbox-gl-native/pull/7676)
+ - Avoid triggering a fling after a scale gesture [#7675](https://github.com/mapbox/mapbox-gl-native/issues/7675)
+* Deselect marker on infowindow click [#7784](https://github.com/mapbox/mapbox-gl-native/issues/7784)
+* Update build tools to Bitrise supported one [#7729](https://github.com/mapbox/mapbox-gl-native/issues/7729)
+* Removal of redudant log statements in native_map_view.cpp [#7801](https://github.com/mapbox/mapbox-gl-native/issues/7801)
+* Invalidate markersviews when updating their position [#7794](https://github.com/mapbox/mapbox-gl-native/issues/7794)
+* Avoid clustering unclusterable GeoJSON [#7633](https://github.com/mapbox/mapbox-gl-native/pull/7633)
+* Prevent null pointer exceptions when receiving connecitivy change events [#6858](https://github.com/mapbox/mapbox-gl-native/issues/6858)
## 4.2.1 - December 22, 2016
@@ -50,7 +67,7 @@ Mapbox Android 4.2.1 is a bugfix release build on top of 4.2.0 and resolves:
## 4.2.0 - December 14, 2016
-Mapbox Android 4.2.0 contains all 4.2.0-beta.3 changes and adds:
+Mapbox Android 4.2.0 contains all 4.2.0-beta.5 changes and adds:
* Adds additional documentation to APIs
* Resolved issue with marker views occasionally not showing up until a gesture was performed on map [#7239](https://github.com/mapbox/mapbox-gl-native/pull/7239)
@@ -58,6 +75,18 @@ Mapbox Android 4.2.0 contains all 4.2.0-beta.3 changes and adds:
* Resolved issue with changing visibility of a layer [#7242](https://github.com/mapbox/mapbox-gl-native/pull/7242)
* Proguard improvement and fixes
+## 4.2.0-beta.5 - October 25, 2016
+
+Mapbox Android 4.2.0-beta.5 adds no new features, only bug fixes.
+
+## 4.2.0-beta.4 - October 25, 2016
+
+Mapbox Android 4.2.0-beta.4 contains all 4.2.0-beta.3 changes and adds:
+
+* Query rendered features by source [#6516](https://github.com/mapbox/mapbox-gl-native/issues/6516)
+* Decreased logging for release builds [#6787](https://github.com/mapbox/mapbox-gl-native/pull/6787)
+* setConnected method to manually set a connected flag [#6618](https://github.com/mapbox/mapbox-gl-native/pull/6618)
+
## 4.2.0-beta.3 - September 21, 2016
Mapbox Android 4.2.0-beta.3 contains all 4.2.0-beta.2 changes and adds:
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index ae02f8765c..6602d919a3 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -1,49 +1,42 @@
apply plugin: 'com.android.library'
-ext {
- supportLibVersion = '25.1.0'
-}
-
dependencies {
compile "com.android.support:support-annotations:${supportLibVersion}"
compile "com.android.support:support-v4:${supportLibVersion}"
compile "com.android.support:design:${supportLibVersion}"
- compile 'com.squareup.okhttp3:okhttp:3.5.0'
- compile 'com.mapzen.android:lost:2.0.0'
- compile 'com.jakewharton.timber:timber:4.3.1'
+ compile rootProject.ext.dep.timber
+ compile rootProject.ext.dep.okhttp3
+ compile rootProject.ext.dep.lost
// Mapbox Android Services (GeoJSON support)
- compile('com.mapbox.mapboxsdk:mapbox-java-geojson:2.0.0-SNAPSHOT@jar') {
+ compile(rootProject.ext.dep.mapboxJavaGeoJSON) {
+ transitive = true
+ }
+
+ // Mapbox Android Services (Telemetry support)
+ compile(rootProject.ext.dep.mapboxAndroidTelemetry) {
transitive = true
}
}
android {
- compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
- buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
- minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK)
- targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
- buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT_BASE", String.format("\"MapboxEventsAndroid/%s\"", project.VERSION_NAME)
- buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME)
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
buildConfigField "String", "GIT_REVISION_SHORT", String.format("\"%s\"", getGitRevision())
}
- android {
- // avoid naming conflicts, force usage of prefix
- resourcePrefix 'mapbox_'
- }
+ // avoid naming conflicts, force usage of prefix
+ resourcePrefix 'mapbox_'
sourceSets {
// limit amount of exposed library resources
main.res.srcDirs += 'src/main/res-public'
}
- repositories {
- mavenCentral()
- }
-
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
@@ -81,4 +74,4 @@ configurations {
apply from: 'gradle-javadoc.gradle'
apply from: 'gradle-publish.gradle'
-apply from: 'gradle-checkstyle.gradle' \ No newline at end of file
+apply from: 'gradle-checkstyle.gradle'
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
index cdcc7f1e23..05037c6be7 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
@@ -12,6 +12,9 @@ task checkstyle(type: Checkstyle) {
source 'src'
include '**/*.java'
exclude '**/gen/**'
+ exclude '**/style/layers/Property.java'
+ exclude '**/style/layers/PropertyFactory.java'
+ exclude '**/style/layers/*Layer.java'
classpath = files()
ignoreFailures = false
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle b/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
index ba7601127c..eeb5e9b4d6 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
@@ -1,6 +1,6 @@
android.libraryVariants.all { variant ->
def name = variant.name
- //noinspection GroovyAssignabilityCheck
+ // noinspection GroovyAssignabilityCheck
task "javadoc$name"(type: Javadoc) {
description = "Generates javadoc for build $name"
failOnError = false
@@ -18,4 +18,4 @@ android.libraryVariants.all { variant ->
options.group("Third Party Libraries", "com.almeros.*")
exclude '**/R.java', '**/BuildConfig.java', 'com/almeros/**'
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-publish.gradle b/platform/android/MapboxGLAndroidSDK/gradle-publish.gradle
index f017434fac..c5037974c0 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-publish.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-publish.gradle
@@ -150,4 +150,4 @@ afterEvaluate { project ->
archives androidSourcesJar
archives androidJavadocsJar
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index 7bdc7ab455..dac39fa60a 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -11,12 +11,6 @@ POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mapbox
POM_DEVELOPER_NAME=Mapbox
-
-ANDROID_MIN_SDK=15
-ANDROID_BUILD_TARGET_SDK_VERSION=25
-ANDROID_BUILD_TOOLS_VERSION=25.0.2
-ANDROID_BUILD_SDK_VERSION=25
-
POM_NAME=Mapbox Android SDK
POM_ARTIFACT_ID=mapbox-android-sdk
POM_PACKAGING=aar
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 9d20e968c8..f954073974 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
@@ -8,8 +8,11 @@ import android.text.TextUtils;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
-import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
+import com.mapbox.services.android.telemetry.MapboxTelemetry;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
public final class Mapbox {
@@ -32,7 +35,9 @@ public final class Mapbox {
if (INSTANCE == null) {
Context appContext = context.getApplicationContext();
INSTANCE = new Mapbox(appContext, accessToken);
- MapboxEventManager.getMapboxEventManager().initialize(appContext, accessToken);
+ LocationEngine locationEngine = new LocationSource(appContext);
+ locationEngine.setPriority(LocationEnginePriority.NO_POWER);
+ MapboxTelemetry.getInstance().initialize(appContext, accessToken, locationEngine);
ConnectivityReceiver.instance(appContext);
}
return INSTANCE;
@@ -101,4 +106,4 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java
new file mode 100644
index 0000000000..2fe5f8f420
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/ArrowDirection.java
@@ -0,0 +1,30 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+class ArrowDirection {
+ @IntDef( {LEFT, RIGHT, TOP, BOTTOM})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Value {
+ }
+
+ static final int LEFT = 0;
+ static final int RIGHT = 1;
+ static final int TOP = 2;
+ static final int BOTTOM = 3;
+
+ @Value
+ private final int value;
+
+ ArrowDirection(@Value int value) {
+ this.value = value;
+ }
+
+ @Value
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java
new file mode 100644
index 0000000000..6fad249780
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Bubble.java
@@ -0,0 +1,311 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+class Bubble extends Drawable {
+
+ private RectF rect;
+ private float arrowWidth;
+ private float arrowHeight;
+ private float arrowPosition;
+ private float cornersRadius;
+ private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private float strokeWidth;
+ private Paint strokePaint;
+ private Path strokePath;
+ private Path path = new Path();
+
+ Bubble(RectF rect, ArrowDirection arrowDirection, float arrowWidth, float arrowHeight, float arrowPosition,
+ float cornersRadius, int bubbleColor, float strokeWidth, int strokeColor) {
+ this.rect = rect;
+ this.arrowWidth = arrowWidth;
+ this.arrowHeight = arrowHeight;
+ this.arrowPosition = arrowPosition;
+ this.cornersRadius = cornersRadius;
+ paint.setColor(bubbleColor);
+ this.strokeWidth = strokeWidth;
+
+ if (strokeWidth > 0) {
+ strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ strokePaint.setColor(strokeColor);
+ strokePath = new Path();
+ initPath(arrowDirection, path, strokeWidth);
+ initPath(arrowDirection, strokePath, 0);
+ } else {
+ initPath(arrowDirection, path, 0);
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (strokeWidth > 0) {
+ canvas.drawPath(strokePath, strokePaint);
+ }
+ canvas.drawPath(path, paint);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ paint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ paint.setColorFilter(cf);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return (int) rect.width();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return (int) rect.height();
+ }
+
+ private void initPath(ArrowDirection arrowDirection, Path path, float strokeWidth) {
+ switch (arrowDirection.getValue()) {
+ case ArrowDirection.LEFT:
+ if (cornersRadius <= 0) {
+ initLeftSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ if (strokeWidth > 0 && strokeWidth > cornersRadius) {
+ initLeftSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ initLeftRoundedPath(rect, path, strokeWidth);
+ break;
+ case ArrowDirection.TOP:
+ if (cornersRadius <= 0) {
+ initTopSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ if (strokeWidth > 0 && strokeWidth > cornersRadius) {
+ initTopSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ initTopRoundedPath(rect, path, strokeWidth);
+ break;
+ case ArrowDirection.RIGHT:
+ if (cornersRadius <= 0) {
+ initRightSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ if (strokeWidth > 0 && strokeWidth > cornersRadius) {
+ initRightSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ initRightRoundedPath(rect, path, strokeWidth);
+ break;
+ case ArrowDirection.BOTTOM:
+ if (cornersRadius <= 0) {
+ initBottomSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ if (strokeWidth > 0 && strokeWidth > cornersRadius) {
+ initBottomSquarePath(rect, path, strokeWidth);
+ break;
+ }
+
+ initBottomRoundedPath(rect, path, strokeWidth);
+ break;
+ }
+ }
+
+ private void initLeftSquarePath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(arrowWidth + rect.left + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.width() - strokeWidth, rect.top + strokeWidth);
+
+ path.lineTo(rect.right - strokeWidth, rect.bottom - strokeWidth);
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, rect.bottom - strokeWidth);
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, arrowHeight + arrowPosition - (strokeWidth / 2));
+ path.lineTo(rect.left + strokeWidth + strokeWidth, arrowPosition + arrowHeight / 2);
+ path.lineTo(rect.left + arrowWidth + strokeWidth, arrowPosition + (strokeWidth / 2));
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, rect.top + strokeWidth);
+
+ path.close();
+ }
+
+ private void initLeftRoundedPath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(arrowWidth + rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.width() - cornersRadius - strokeWidth, rect.top + strokeWidth);
+ path.arcTo(new RectF(rect.right - cornersRadius, rect.top + strokeWidth, rect.right - strokeWidth,
+ cornersRadius + rect.top), 270, 90);
+
+ path.lineTo(rect.right - strokeWidth, rect.bottom - cornersRadius - strokeWidth);
+ path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius,
+ rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90);
+
+ path.lineTo(rect.left + arrowWidth + cornersRadius + strokeWidth, rect.bottom - strokeWidth);
+
+ path.arcTo(new RectF(rect.left + arrowWidth + strokeWidth, rect.bottom - cornersRadius,
+ cornersRadius + rect.left + arrowWidth, rect.bottom - strokeWidth), 90, 90);
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, arrowHeight + arrowPosition - (strokeWidth / 2));
+
+ path.lineTo(rect.left + strokeWidth + strokeWidth, arrowPosition + arrowHeight / 2);
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, arrowPosition + (strokeWidth / 2));
+
+ path.lineTo(rect.left + arrowWidth + strokeWidth, rect.top + cornersRadius + strokeWidth);
+
+ path.arcTo(new RectF(rect.left + arrowWidth + strokeWidth, rect.top + strokeWidth, cornersRadius
+ + rect.left + arrowWidth, cornersRadius + rect.top), 180, 90);
+
+ path.close();
+ }
+
+ private void initTopSquarePath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + arrowPosition + strokeWidth, rect.top + arrowHeight + strokeWidth);
+
+ path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.top + arrowHeight + strokeWidth);
+ path.lineTo(rect.left + arrowWidth / 2 + arrowPosition, rect.top + strokeWidth + strokeWidth);
+ path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.top + arrowHeight + strokeWidth);
+ path.lineTo(rect.right - strokeWidth, rect.top + arrowHeight + strokeWidth);
+
+ path.lineTo(rect.right - strokeWidth, rect.bottom - strokeWidth);
+
+ path.lineTo(rect.left + strokeWidth, rect.bottom - strokeWidth);
+
+ path.lineTo(rect.left + strokeWidth, rect.top + arrowHeight + strokeWidth);
+
+ path.lineTo(rect.left + arrowPosition + strokeWidth, rect.top + arrowHeight + strokeWidth);
+
+ path.close();
+ }
+
+ private void initTopRoundedPath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + Math.min(arrowPosition, cornersRadius) + strokeWidth, rect.top + arrowHeight
+ + strokeWidth);
+ path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.top + arrowHeight + strokeWidth);
+ path.lineTo(rect.left + arrowWidth / 2 + arrowPosition, rect.top + strokeWidth + strokeWidth);
+ path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.top + arrowHeight + strokeWidth);
+ path.lineTo(rect.right - cornersRadius - strokeWidth, rect.top + arrowHeight + strokeWidth);
+
+ path.arcTo(new RectF(rect.right - cornersRadius,
+ rect.top + arrowHeight + strokeWidth, rect.right - strokeWidth, cornersRadius + rect.top + arrowHeight),
+ 270, 90);
+ path.lineTo(rect.right - strokeWidth, rect.bottom - cornersRadius - strokeWidth);
+
+ path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius,
+ rect.right - strokeWidth, rect.bottom - strokeWidth), 0, 90);
+ path.lineTo(rect.left + cornersRadius + strokeWidth, rect.bottom - strokeWidth);
+
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius,
+ cornersRadius + rect.left, rect.bottom - strokeWidth), 90, 90);
+
+ path.lineTo(rect.left + strokeWidth, rect.top + arrowHeight + cornersRadius + strokeWidth);
+
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.top + arrowHeight + strokeWidth, cornersRadius
+ + rect.left, cornersRadius + rect.top + arrowHeight), 180, 90);
+
+ path.close();
+ }
+
+ private void initRightSquarePath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.width() - arrowWidth - strokeWidth, rect.top + strokeWidth);
+
+ path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + (strokeWidth / 2));
+ path.lineTo(rect.right - strokeWidth - strokeWidth, arrowPosition + arrowHeight / 2);
+ path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + arrowHeight - (strokeWidth / 2));
+
+ path.lineTo(rect.right - arrowWidth - strokeWidth, rect.bottom - strokeWidth);
+
+ path.lineTo(rect.left + strokeWidth, rect.bottom - strokeWidth);
+ path.lineTo(rect.left + strokeWidth, rect.top + strokeWidth);
+
+ path.close();
+ }
+
+ private void initRightRoundedPath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.width() - cornersRadius - arrowWidth - strokeWidth, rect.top + strokeWidth);
+ path.arcTo(new RectF(rect.right - cornersRadius - arrowWidth,
+ rect.top + strokeWidth, rect.right - arrowWidth - strokeWidth, cornersRadius + rect.top), 270, 90);
+
+ path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + (strokeWidth / 2));
+ path.lineTo(rect.right - strokeWidth - strokeWidth, arrowPosition + arrowHeight / 2);
+ path.lineTo(rect.right - arrowWidth - strokeWidth, arrowPosition + arrowHeight - (strokeWidth / 2));
+ path.lineTo(rect.right - arrowWidth - strokeWidth, rect.bottom - cornersRadius - strokeWidth);
+
+ path.arcTo(new RectF(rect.right - cornersRadius - arrowWidth, rect.bottom - cornersRadius,
+ rect.right - arrowWidth - strokeWidth, rect.bottom - strokeWidth), 0, 90);
+ path.lineTo(rect.left + arrowWidth + strokeWidth, rect.bottom - strokeWidth);
+
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius,
+ cornersRadius + rect.left, rect.bottom - strokeWidth), 90, 90);
+
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.top + strokeWidth, cornersRadius
+ + rect.left, cornersRadius + rect.top), 180, 90);
+ path.close();
+ }
+
+ private void initBottomSquarePath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.right - strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.right - strokeWidth, rect.bottom - arrowHeight - strokeWidth);
+
+ path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth);
+ path.lineTo(rect.left + arrowPosition + arrowWidth / 2, rect.bottom - strokeWidth - strokeWidth);
+ path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth);
+ path.lineTo(rect.left + arrowPosition + strokeWidth, rect.bottom - arrowHeight - strokeWidth);
+
+ path.lineTo(rect.left + strokeWidth, rect.bottom - arrowHeight - strokeWidth);
+ path.lineTo(rect.left + strokeWidth, rect.top + strokeWidth);
+ path.close();
+ }
+
+ private void initBottomRoundedPath(RectF rect, Path path, float strokeWidth) {
+ path.moveTo(rect.left + cornersRadius + strokeWidth, rect.top + strokeWidth);
+ path.lineTo(rect.width() - cornersRadius - strokeWidth, rect.top + strokeWidth);
+ path.arcTo(new RectF(rect.right - cornersRadius,
+ rect.top + strokeWidth, rect.right - strokeWidth, cornersRadius + rect.top), 270, 90);
+
+ path.lineTo(rect.right - strokeWidth, rect.bottom - arrowHeight - cornersRadius - strokeWidth);
+ path.arcTo(new RectF(rect.right - cornersRadius, rect.bottom - cornersRadius - arrowHeight,
+ rect.right - strokeWidth, rect.bottom - arrowHeight - strokeWidth), 0, 90);
+
+ path.lineTo(rect.left + arrowWidth + arrowPosition - (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth);
+ path.lineTo(rect.left + arrowPosition + arrowWidth / 2, rect.bottom - strokeWidth - strokeWidth);
+ path.lineTo(rect.left + arrowPosition + (strokeWidth / 2), rect.bottom - arrowHeight - strokeWidth);
+ path.lineTo(rect.left + Math.min(cornersRadius, arrowPosition) + strokeWidth, rect.bottom - arrowHeight
+ - strokeWidth);
+
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.bottom - cornersRadius - arrowHeight,
+ cornersRadius + rect.left, rect.bottom - arrowHeight - strokeWidth), 90, 90);
+ path.lineTo(rect.left + strokeWidth, rect.top + cornersRadius + strokeWidth);
+ path.arcTo(new RectF(rect.left + strokeWidth, rect.top + strokeWidth, cornersRadius
+ + rect.left, cornersRadius + rect.top), 180, 90);
+ path.close();
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
new file mode 100644
index 0000000000..2e6445170f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
@@ -0,0 +1,231 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.widget.LinearLayout;
+
+import com.mapbox.mapboxsdk.R;
+
+/**
+ * Bubble View for Android with custom stroke width and color, arrow size, position and direction.
+ */
+class BubbleLayout extends LinearLayout {
+
+ public static final float DEFAULT_STROKE_WIDTH = -1;
+ private ArrowDirection arrowDirection;
+ private float arrowWidth;
+ private float arrowHeight;
+ private float arrowPosition;
+ private float cornersRadius;
+ private Bubble bubble;
+ private int bubbleColor;
+ private float strokeWidth;
+ private int strokeColor;
+
+ public BubbleLayout(Context context) {
+ this(context, null, 0);
+ }
+
+ public BubbleLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public BubbleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.mapbox_BubbleLayout);
+ @ArrowDirection.Value
+ int location = a.getInt(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowDirection,
+ ArrowDirection.LEFT);
+ arrowDirection = new ArrowDirection(location);
+ arrowWidth = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowWidth,
+ convertDpToPixel(8, context));
+ arrowHeight = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowHeight,
+ convertDpToPixel(8, context));
+ arrowPosition = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_arrowPosition,
+ convertDpToPixel(12, context));
+ cornersRadius = a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_cornersRadius, 0);
+ bubbleColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_bubbleColor, Color.WHITE);
+ strokeWidth =
+ a.getDimension(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeWidth, DEFAULT_STROKE_WIDTH);
+ strokeColor = a.getColor(R.styleable.mapbox_BubbleLayout_mapbox_bl_strokeColor, Color.GRAY);
+
+ a.recycle();
+ initPadding();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ initDrawable(0, getWidth(), 0, getHeight());
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (bubble != null) {
+ bubble.draw(canvas);
+ }
+ super.dispatchDraw(canvas);
+ }
+
+ static float convertDpToPixel(float dp, Context context) {
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
+ }
+
+ public ArrowDirection getArrowDirection() {
+ return arrowDirection;
+ }
+
+ public BubbleLayout setArrowDirection(ArrowDirection arrowDirection) {
+ resetPadding();
+ this.arrowDirection = arrowDirection;
+ initPadding();
+ return this;
+ }
+
+ public float getArrowWidth() {
+ return arrowWidth;
+ }
+
+ public BubbleLayout setArrowWidth(float arrowWidth) {
+ resetPadding();
+ this.arrowWidth = arrowWidth;
+ initPadding();
+ return this;
+ }
+
+ public float getArrowHeight() {
+ return arrowHeight;
+ }
+
+ public BubbleLayout setArrowHeight(float arrowHeight) {
+ resetPadding();
+ this.arrowHeight = arrowHeight;
+ initPadding();
+ return this;
+ }
+
+ public float getArrowPosition() {
+ return arrowPosition;
+ }
+
+ public BubbleLayout setArrowPosition(float arrowPosition) {
+ resetPadding();
+ this.arrowPosition = arrowPosition;
+ initPadding();
+ return this;
+ }
+
+ public float getCornersRadius() {
+ return cornersRadius;
+ }
+
+ public BubbleLayout setCornersRadius(float cornersRadius) {
+ this.cornersRadius = cornersRadius;
+ requestLayout();
+ return this;
+ }
+
+ public int getBubbleColor() {
+ return bubbleColor;
+ }
+
+ public BubbleLayout setBubbleColor(int bubbleColor) {
+ this.bubbleColor = bubbleColor;
+ requestLayout();
+ return this;
+ }
+
+ public float getStrokeWidth() {
+ return strokeWidth;
+ }
+
+ public BubbleLayout setStrokeWidth(float strokeWidth) {
+ resetPadding();
+ this.strokeWidth = strokeWidth;
+ initPadding();
+ return this;
+ }
+
+ public int getStrokeColor() {
+ return strokeColor;
+ }
+
+ public BubbleLayout setStrokeColor(int strokeColor) {
+ this.strokeColor = strokeColor;
+ requestLayout();
+ return this;
+ }
+
+ private void initPadding() {
+ int paddingLeft = getPaddingLeft();
+ int paddingRight = getPaddingRight();
+ int paddingTop = getPaddingTop();
+ int paddingBottom = getPaddingBottom();
+ switch (arrowDirection.getValue()) {
+ case ArrowDirection.LEFT:
+ paddingLeft += arrowWidth;
+ break;
+ case ArrowDirection.RIGHT:
+ paddingRight += arrowWidth;
+ break;
+ case ArrowDirection.TOP:
+ paddingTop += arrowHeight;
+ break;
+ case ArrowDirection.BOTTOM:
+ paddingBottom += arrowHeight;
+ break;
+ }
+ if (strokeWidth > 0) {
+ paddingLeft += strokeWidth;
+ paddingRight += strokeWidth;
+ paddingTop += strokeWidth;
+ paddingBottom += strokeWidth;
+ }
+ setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
+
+ private void initDrawable(int left, int right, int top, int bottom) {
+ if (right < left || bottom < top) {
+ return;
+ }
+
+ RectF rectF = new RectF(left, top, right, bottom);
+ bubble = new Bubble(rectF, arrowDirection, arrowWidth, arrowHeight, arrowPosition, cornersRadius,
+ bubbleColor, strokeWidth, strokeColor);
+ }
+
+ private void resetPadding() {
+ int paddingLeft = getPaddingLeft();
+ int paddingRight = getPaddingRight();
+ int paddingTop = getPaddingTop();
+ int paddingBottom = getPaddingBottom();
+ switch (arrowDirection.getValue()) {
+ case ArrowDirection.LEFT:
+ paddingLeft -= arrowWidth;
+ break;
+ case ArrowDirection.RIGHT:
+ paddingRight -= arrowWidth;
+ break;
+ case ArrowDirection.TOP:
+ paddingTop -= arrowHeight;
+ break;
+ case ArrowDirection.BOTTOM:
+ paddingBottom -= arrowHeight;
+ break;
+ }
+ if (strokeWidth > 0) {
+ paddingLeft -= strokeWidth;
+ paddingRight -= strokeWidth;
+ paddingTop -= strokeWidth;
+ paddingBottom -= strokeWidth;
+ }
+ setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java
new file mode 100644
index 0000000000..215445abaa
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubblePopupHelper.java
@@ -0,0 +1,33 @@
+package com.mapbox.mapboxsdk.annotations;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.view.ViewGroup;
+import android.widget.PopupWindow;
+
+import com.mapbox.mapboxsdk.R;
+
+class BubblePopupHelper {
+
+ static PopupWindow create(@NonNull Context context, @NonNull BubbleLayout bubbleLayout) {
+ PopupWindow popupWindow = new PopupWindow(context);
+
+ popupWindow.setContentView(bubbleLayout);
+ popupWindow.setOutsideTouchable(true);
+ popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
+ popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+ popupWindow.setAnimationStyle(android.R.style.Animation_Dialog);
+ // change background color to transparent
+ Drawable drawable;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ drawable = context.getDrawable(R.drawable.mapbox_popup_window_transparent);
+ } else {
+ drawable = context.getResources().getDrawable(R.drawable.mapbox_popup_window_transparent);
+ }
+ popupWindow.setBackgroundDrawable(drawable);
+
+ return popupWindow;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
index 052d5592e4..57aa512401 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
@@ -3,8 +3,6 @@ package com.mapbox.mapboxsdk.annotations;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -23,7 +21,10 @@ import java.io.IOException;
import java.io.InputStream;
/**
- * Factory for creating {@link Icon} objects.
+ * Factory for creating Icons from bitmap images.
+ * <p>
+ * {@link Icon} is used to display bitmaps on top of the map using {@link Marker} and {@link MarkerView}.
+ * </p>
*
* @see Icon
*/
@@ -33,23 +34,23 @@ public final class IconFactory {
public static final Bitmap ICON_MARKERVIEW_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
public static final String ICON_MARKERVIEW_ID = ICON_ID_PREFIX + "marker_view";
- private Context mContext;
- private static IconFactory sInstance;
- private Icon mDefaultMarker;
- private Icon mDefaultMarkerView;
- private BitmapFactory.Options mOptions;
+ private Context context;
+ private static IconFactory instance;
+ private Icon defaultMarker;
+ private Icon defaultMarkerView;
+ private BitmapFactory.Options options;
- private int mNextId = 0;
+ private int nextId = 0;
public static synchronized IconFactory getInstance(@NonNull Context context) {
- if (sInstance == null) {
- sInstance = new IconFactory(context.getApplicationContext());
+ if (instance == null) {
+ instance = new IconFactory(context.getApplicationContext());
}
- return sInstance;
+ return instance;
}
private IconFactory(@NonNull Context context) {
- mContext = context;
+ this.context = context;
DisplayMetrics realMetrics = null;
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -60,12 +61,12 @@ public final class IconFactory {
}
wm.getDefaultDisplay().getMetrics(metrics);
- mOptions = new BitmapFactory.Options();
- mOptions.inScaled = true;
- mOptions.inDensity = DisplayMetrics.DENSITY_DEFAULT;
- mOptions.inTargetDensity = metrics.densityDpi;
+ options = new BitmapFactory.Options();
+ options.inScaled = true;
+ options.inDensity = DisplayMetrics.DENSITY_DEFAULT;
+ options.inTargetDensity = metrics.densityDpi;
if (realMetrics != null) {
- mOptions.inScreenDensity = realMetrics.densityDpi;
+ options.inScreenDensity = realMetrics.densityDpi;
}
}
@@ -76,73 +77,27 @@ public final class IconFactory {
* @return The {@link Icon} using the given Bitmap image.
*/
public Icon fromBitmap(@NonNull Bitmap bitmap) {
- if (mNextId < 0) {
+ if (nextId < 0) {
throw new TooManyIconsException();
}
- String id = ICON_ID_PREFIX + ++mNextId;
+ String id = ICON_ID_PREFIX + ++nextId;
return new Icon(id, bitmap);
}
/**
- * Create an {@link Icon} from a given {@link Drawable}.
- *
- * @param drawable A {@link Drawable} object used for creating the {@link Icon}.
- * @return {@link Icon} with the provided {@link Drawable}.
- */
- public Icon fromDrawable(@NonNull Drawable drawable) {
- int width = drawable.getIntrinsicWidth();
- int height = drawable.getIntrinsicHeight();
- return fromDrawable(drawable, width, height);
- }
-
- /**
- * Create an {@link Icon} from a given {@link Drawable}.
- *
- * @param drawable A {@link Drawable} object used for creating the {@link Icon}.
- * @param width An integer greater then zero defining the {@link Icon} width.
- * @param height An integer greater then zero defining the {@link Icon} height.
- * @return {@link Icon} with the provided {@link Drawable}.
- */
- public Icon fromDrawable(@NonNull Drawable drawable, int width, int height) {
- if ((width < 0) || (height < 0)) {
- return null;
- }
-
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- Rect temp = drawable.getBounds();
- Rect bounds = new Rect(0, 0, width, height);
- drawable.setBounds(bounds);
- drawable.draw(canvas);
- drawable.setBounds(temp);
- return fromBitmap(bitmap);
- }
-
- /**
* Create an {@link Icon} using the resource ID of a Bitmap image.
*
* @param resourceId The resource ID of a Bitmap image.
* @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load.
*/
public Icon fromResource(@DrawableRes int resourceId) {
- Drawable drawable = ContextCompat.getDrawable(mContext, resourceId);
- Bitmap bitmap;
+ Drawable drawable = ContextCompat.getDrawable(context, resourceId);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
- bitmap = bitmapDrawable.getBitmap();
+ return fromBitmap(bitmapDrawable.getBitmap());
} else {
- if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
- bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
- } else {
- bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
- Bitmap.Config.ARGB_8888);
- }
-
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
+ throw new IllegalArgumentException("Failed to decode image. The resource provided must be a Bitmap.");
}
- return fromBitmap(bitmap);
}
/**
@@ -151,10 +106,10 @@ public final class IconFactory {
* @return An {@link Icon} with the default {@link Marker} icon.
*/
public Icon defaultMarker() {
- if (mDefaultMarker == null) {
- mDefaultMarker = fromResource(R.drawable.mapbox_marker_icon_default);
+ if (defaultMarker == null) {
+ defaultMarker = fromResource(R.drawable.mapbox_marker_icon_default);
}
- return mDefaultMarker;
+ return defaultMarker;
}
/**
@@ -163,14 +118,14 @@ public final class IconFactory {
* @return An {@link Icon} with the default {@link MarkerView} icon.
*/
public Icon defaultMarkerView() {
- if (mDefaultMarkerView == null) {
- mDefaultMarkerView = fromResource(R.drawable.mapbox_markerview_icon_default);
+ if (defaultMarkerView == null) {
+ defaultMarkerView = fromResource(R.drawable.mapbox_markerview_icon_default);
}
- return mDefaultMarkerView;
+ return defaultMarkerView;
}
private Icon fromInputStream(@NonNull InputStream is) {
- Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions);
+ Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
return fromBitmap(bitmap);
}
@@ -183,7 +138,7 @@ public final class IconFactory {
public Icon fromAsset(@NonNull String assetName) {
InputStream is;
try {
- is = mContext.getAssets().open(assetName);
+ is = context.getAssets().open(assetName);
} catch (IOException ioException) {
return null;
}
@@ -198,7 +153,7 @@ public final class IconFactory {
* load.
*/
public Icon fromPath(@NonNull String absolutePath) {
- Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, mOptions);
+ Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, options);
return fromBitmap(bitmap);
}
@@ -209,12 +164,12 @@ public final class IconFactory {
* @param fileName The name of the Bitmap image file.
* @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load.
* @see <a href="https://developer.android.com/guide/topics/data/data-storage.html#filesInternal">
- * Using the Internal Storage</a>
+ * Using the Internal Storage</a>
*/
public Icon fromFile(@NonNull String fileName) {
FileInputStream is;
try {
- is = mContext.openFileInput(fileName);
+ is = context.openFileInput(fileName);
} catch (FileNotFoundException fileNotFoundException) {
return null;
}
@@ -232,4 +187,5 @@ public final class IconFactory {
public static Icon recreate(@NonNull String iconId, @NonNull Bitmap bitmap) {
return new Icon(iconId, bitmap);
}
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
index 4e080d98f6..cf42bfe738 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java
@@ -133,7 +133,7 @@ public class InfoWindow {
float x = coordinates.x - (view.getMeasuredWidth() / 2) + offsetX;
float y = coordinates.y - view.getMeasuredHeight() + offsetY;
- if (view instanceof InfoWindowView) {
+ if (view instanceof BubbleLayout) {
// only apply repositioning/margin for InfoWindowView
Resources resources = mapView.getContext().getResources();
@@ -187,8 +187,7 @@ public class InfoWindow {
}
// Adjust tipView
- InfoWindowView infoWindowView = (InfoWindowView) view;
- infoWindowView.setTipViewMarginLeft((int) tipViewMarginLeft);
+ ((BubbleLayout) view).setArrowPosition(tipViewMarginLeft);
}
// set anchor popupwindowview
@@ -198,7 +197,7 @@ public class InfoWindow {
// Calculate x-offset for update method
viewWidthOffset = x - coordinates.x - offsetX;
- close(); //if it was already opened
+ close(); // if it was already opened
mapView.addView(view, lp);
isVisible = true;
}
@@ -284,7 +283,7 @@ public class InfoWindow {
if (mapboxMap != null && marker != null && view != null) {
coordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
- if (view instanceof InfoWindowView) {
+ if (view instanceof BubbleLayout) {
view.setX(coordinates.x + viewWidthOffset - markerWidthOffset);
} else {
view.setX(coordinates.x - (view.getMeasuredWidth() / 2) - markerWidthOffset);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java
deleted file mode 100644
index abcebfec83..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package com.mapbox.mapboxsdk.annotations;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.util.AttributeSet;
-import android.view.View;
-
-import com.mapbox.mapboxsdk.R;
-
-final class InfoWindowTipView extends View {
-
- private Paint mPaint;
- private Path mPath;
- private int mLineWidth;
-
- public InfoWindowTipView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mPath = new Path();
- mLineWidth = (int) context.getResources().getDimension(R.dimen.mapbox_infowindow_line_width);
- mPaint = new Paint();
- mPaint.setColor(Color.WHITE);
- mPaint.setAntiAlias(true);
- mPaint.setStrokeWidth(0.0f);
- mPaint.setStyle(Paint.Style.FILL);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- int height = getMeasuredHeight();
- int width = getMeasuredWidth();
-
- mPath.rewind();
-
- this.mPaint.setColor(Color.WHITE);
- this.mPaint.setAntiAlias(true);
- this.mPaint.setStrokeWidth(0.0f);
- this.mPaint.setStyle(Paint.Style.FILL);
-
- mPath.moveTo(0, 0);
- mPath.lineTo(width, 0);
- mPath.lineTo((width / 2), height);
- mPath.lineTo(0, 0);
- canvas.drawPath(mPath, this.mPaint);
-
- mPath.rewind();
-
- this.mPaint.setColor(Color.parseColor("#C2C2C2"));
- this.mPaint.setAntiAlias(true);
- this.mPaint.setStrokeWidth(mLineWidth);
- this.mPaint.setStyle(Paint.Style.STROKE);
-
- mPath.moveTo(0, 0);
- mPath.lineTo(width / 2, height);
- mPath.lineTo(width, 0);
- canvas.drawPath(mPath, this.mPaint);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java
deleted file mode 100644
index d1a59aae4e..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.mapbox.mapboxsdk.annotations;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.widget.RelativeLayout;
-
-import com.mapbox.mapboxsdk.R;
-
-class InfoWindowView extends RelativeLayout {
-
- private InfoWindowTipView mTipView;
-
- public InfoWindowView(Context context) {
- this(context, null);
- }
-
- public InfoWindowView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public InfoWindowView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- initialize(context);
- }
-
- private void initialize(Context context) {
- LayoutInflater.from(context).inflate(R.layout.mapbox_infowindow_content, this);
- mTipView = (InfoWindowTipView) findViewById(R.id.infowindow_tipview);
- }
-
- void setTipViewMarginLeft(int marginLeft) {
- RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTipView.getLayoutParams();
- layoutParams.leftMargin = marginLeft;
- // This is a bit of a hack but prevents an occasional gap between the InfoWindow
- layoutParams.topMargin = (int) getResources().getDimension(R.dimen.mapbox_infowindow_offset);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
index edf118205b..18f74cd990 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java
@@ -30,6 +30,8 @@ public class Marker extends Annotation {
private LatLng position;
private String snippet;
private Icon icon;
+ //Redundantly stored for JNI access
+ private String iconId;
private String title;
private InfoWindow infoWindow;
@@ -51,24 +53,19 @@ public class Marker extends Annotation {
* @param baseMarkerOptions The builder used to construct the Marker.
*/
public Marker(BaseMarkerOptions baseMarkerOptions) {
- position = baseMarkerOptions.position;
- snippet = baseMarkerOptions.snippet;
- icon = baseMarkerOptions.icon;
- title = baseMarkerOptions.title;
+ this(baseMarkerOptions.position, baseMarkerOptions.icon, baseMarkerOptions.title, baseMarkerOptions.snippet);
}
Marker(BaseMarkerViewOptions baseMarkerViewOptions) {
- position = baseMarkerViewOptions.position;
- snippet = baseMarkerViewOptions.snippet;
- icon = baseMarkerViewOptions.icon;
- title = baseMarkerViewOptions.title;
+ this(baseMarkerViewOptions.position, baseMarkerViewOptions.icon,
+ baseMarkerViewOptions.title, baseMarkerViewOptions.snippet);
}
Marker(LatLng position, Icon icon, String title, String snippet) {
this.position = position;
- this.icon = icon;
this.title = title;
this.snippet = snippet;
+ setIcon(icon);
}
/**
@@ -148,6 +145,7 @@ public class Marker extends Annotation {
*/
public void setIcon(@Nullable Icon icon) {
this.icon = icon;
+ this.iconId = icon != null ? icon.getId() : null;
MapboxMap map = getMapboxMap();
if (map != null) {
map.updateMarker(this);
@@ -240,7 +238,7 @@ public class Marker extends Annotation {
private InfoWindow getInfoWindow(@NonNull MapView mapView) {
if (infoWindow == null && mapView.getContext() != null) {
- infoWindow = new InfoWindow(mapView, R.layout.mapbox_infowindow_view, getMapboxMap());
+ infoWindow = new InfoWindow(mapView, R.layout.mapbox_infowindow_content, getMapboxMap());
}
return infoWindow;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index c1b643eb4c..220d3322cb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -266,18 +266,9 @@ public class MarkerView extends Marker {
* @param rotation the rotation value to animate to.
*/
public void setRotation(float rotation) {
- // limit to 0 - 360 degrees
- float newRotation = rotation;
- while (newRotation > 360) {
- newRotation -= 360;
- }
- while (newRotation < 0) {
- newRotation += 360;
- }
-
- this.rotation = newRotation;
+ this.rotation = rotation;
if (markerViewManager != null) {
- markerViewManager.animateRotationBy(this, newRotation);
+ markerViewManager.setRotation(this, rotation);
}
}
@@ -342,6 +333,7 @@ public class MarkerView extends Marker {
public void setPosition(LatLng position) {
super.setPosition(position);
if (markerViewManager != null) {
+ markerViewManager.setWaitingForRenderInvoke(true);
markerViewManager.update();
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
index ad221691b4..17a1866379 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
@@ -125,6 +125,14 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
}
}
+ public void setRotation(@NonNull MarkerView marker, float rotation) {
+ View convertView = markerViewMap.get(marker);
+ if (convertView != null) {
+ convertView.animate().cancel();
+ convertView.setRotation(rotation);
+ }
+ }
+
/**
* Animate a MarkerView to a given alpha value.
* <p>
@@ -466,7 +474,6 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
if (adapter.getMarkerClass().equals(marker.getClass())) {
adapter.prepareViewForReuse(marker, convertView);
adapter.releaseView(convertView);
- marker.setMapboxMap(null);
iterator.remove();
}
}
@@ -573,7 +580,7 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
if (view != null) {
if (marker.getWidth() == 0) {
if (view.getMeasuredWidth() == 0) {
- //Ensure the marker's view is measured first
+ // Ensure the marker's view is measured first
view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
}
marker.setWidth(view.getMeasuredWidth());
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index 79045b68bb..74170bb72b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -7,9 +7,7 @@ import android.os.Parcelable;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.utils.MathUtils;
-
-import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing;
+import com.mapbox.services.android.telemetry.utils.MathUtils;
/**
* Resembles the position, angle, zoom and tilt of the user's viewpoint.
@@ -244,8 +242,8 @@ public final class CameraPosition implements Parcelable {
public Builder(double[] nativeCameraValues) {
super();
if (nativeCameraValues != null && nativeCameraValues.length == 5) {
- target(new LatLng(nativeCameraValues[0], nativeCameraValues[1]));
- bearing(convertNativeBearing(nativeCameraValues[2]));
+ target(new LatLng(nativeCameraValues[0], nativeCameraValues[1]).wrap());
+ bearing(MathUtils.convertNativeBearing(nativeCameraValues[2]));
tilt(nativeCameraValues[3]);
zoom(nativeCameraValues[4]);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index aecc51530b..ef8a4d58e8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -11,7 +11,7 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Projection;
import com.mapbox.mapboxsdk.maps.UiSettings;
-import com.mapbox.mapboxsdk.utils.MathUtils;
+import com.mapbox.services.android.telemetry.utils.MathUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -259,7 +259,7 @@ public final class CameraUpdateFactory {
float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width;
float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height;
minScale = scaleX < scaleY ? scaleX : scaleY;
- zoom = calculateZoom(mapboxMap, minScale);
+ zoom = projection.calculateZoom(minScale);
zoom = MathUtils.clamp(zoom, mapboxMap.getMinZoomLevel(), mapboxMap.getMaxZoomLevel());
}
@@ -277,16 +277,6 @@ public final class CameraUpdateFactory {
.bearing(0)
.build();
}
-
- /**
- * Calculates a zoom level based on minimum scale and current scale from MapView
- *
- * @param minScale The minimum scale to calculate the zoom level.
- * @return zoom level that fits the MapView.
- */
- public double calculateZoom(MapboxMap mapboxMap, float minScale) {
- return Math.log(mapboxMap.getCameraPosition().zoom * minScale) / Math.log(2);
- }
}
static final class CameraMoveUpdate implements CameraUpdate {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java
deleted file mode 100644
index 009ae936d5..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.mapbox.mapboxsdk.constants;
-
-/**
- * GeoConstants exposes constants for doing locational calculations on Earth
- */
-public class GeoConstants {
-
- /**
- * The <a href='http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius'>equatorial radius</a>
- * value in meters
- */
- public static final int RADIUS_EARTH_METERS = 6378137;
-
- /**
- * The minimum latitude on Earth. This is the minimum latitude representable
- * by Mapbox GL's Mercator projection, because the projection distorts latitude
- * near the poles towards infinity.
- */
- public static final double MIN_LATITUDE = -85.05112878;
-
- /**
- * The maximum latitude on Earth. This is the maximum latitude representable
- * by Mapbox GL's Mercator projection, because the projection distorts latitude
- * near the poles towards infinity.
- */
- public static final double MAX_LATITUDE = 85.05112878;
-
- /**
- * The minimum longitude on Earth
- */
- public static final double MIN_LONGITUDE = -180;
-
- /**
- * The maximum longitude on Earth
- */
- public static final double MAX_LONGITUDE = 180;
-
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
index fbf307541b..0bd9523f4f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
@@ -13,16 +13,6 @@ public class MapboxConstants {
public static final Locale MAPBOX_LOCALE = Locale.US;
/**
- * Key used to store staging data server url in AndroidManifest.xml
- */
- public static final String KEY_META_DATA_STAGING_SERVER = "com.mapbox.TestEventsServer";
-
- /**
- * Key used to store staging data server access token in AndroidManifest.xml
- */
- public static final String KEY_META_DATA_STAGING_ACCESS_TOKEN = "com.mapbox.TestEventsAccessToken";
-
- /**
* Key used to switch storage to external in AndroidManifest.xml
*/
public static final String KEY_META_DATA_SET_STORAGE_EXTERNAL = "com.mapbox.SetStorageExternal";
@@ -103,48 +93,45 @@ public class MapboxConstants {
public static final String FRAG_ARG_MAPBOXMAPOPTIONS = "MapboxMapOptions";
// Save instance state keys
- public static final String STATE_HAS_SAVED_STATE = "savedState";
- public static final String STATE_CAMERA_POSITION = "cameraPosition";
- public static final String STATE_ZOOM_ENABLED = "zoomEnabled";
- public static final String STATE_ZOOM_ENABLED_CHANGE = "zoomEnabledChange";
- public static final String STATE_SCROLL_ENABLED = "scrollEnabled";
- public static final String STATE_SCROLL_ENABLED_CHANGE = "scrollEnabledChange";
- public static final String STATE_ROTATE_ENABLED = "rotateEnabled";
- public static final String STATE_ROTATE_ENABLED_CHANGE = "rotateEnabledChange";
- public static final String STATE_TILT_ENABLED = "tiltEnabled";
- public static final String STATE_TILT_ENABLED_CHANGE = "tiltEnabledChange";
- public static final String STATE_ZOOM_CONTROLS_ENABLED = "zoomControlsEnabled";
- public static final String STATE_DEBUG_ACTIVE = "debugActive";
- public static final String STATE_STYLE_URL = "styleUrl";
- public static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled";
- public static final String STATE_MY_LOCATION_TRACKING_MODE = "myLocationTracking";
- public static final String STATE_MY_BEARING_TRACKING_MODE = "myBearingTracking";
- public static final String STATE_MY_LOCATION_TRACKING_DISMISS = "myLocationTrackingDismiss";
- public static final String STATE_MY_BEARING_TRACKING_DISMISS = "myBearingTrackingDismiss";
- public static final String STATE_COMPASS_ENABLED = "compassEnabled";
- public static final String STATE_COMPASS_GRAVITY = "compassGravity";
- public static final String STATE_COMPASS_MARGIN_LEFT = "compassMarginLeft";
- public static final String STATE_COMPASS_MARGIN_TOP = "compassMarginTop";
- public static final String STATE_COMPASS_MARGIN_RIGHT = "compassMarginRight";
- public static final String STATE_COMPASS_MARGIN_BOTTOM = "compassMarginBottom";
- public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "compassFade";
- public static final String STATE_LOGO_GRAVITY = "logoGravity";
- public static final String STATE_LOGO_MARGIN_LEFT = "logoMarginLeft";
- public static final String STATE_LOGO_MARGIN_TOP = "logoMarginTop";
- public static final String STATE_LOGO_MARGIN_RIGHT = "logoMarginRight";
- public static final String STATE_LOGO_MARGIN_BOTTOM = "logoMarginBottom";
- public static final String STATE_LOGO_ENABLED = "logoEnabled";
- public static final String STATE_ATTRIBUTION_GRAVITY = "attrGravity";
- public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "attrMarginLeft";
- public static final String STATE_ATTRIBUTION_MARGIN_TOP = "attrMarginTop";
- public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "attrMarginRight";
- public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "atrrMarginBottom";
- public static final String STATE_ATTRIBUTION_ENABLED = "atrrEnabled";
-
- public static final String MAPBOX_SHARED_PREFERENCES_FILE = "MapboxSharedPreferences";
- public static final String MAPBOX_SHARED_PREFERENCE_KEY_VENDORID = "mapboxVendorId";
- public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED = "mapboxTelemetryEnabled";
- public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL = "mapboxTelemetryStagingUrl";
- public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN =
- "mapboxTelemetryStagingAccessToken";
+ public static final String STATE_HAS_SAVED_STATE = "mapbox_savedState";
+ public static final String STATE_CAMERA_POSITION = "mapbox_cameraPosition";
+ public static final String STATE_ZOOM_ENABLED = "mapbox_zoomEnabled";
+ public static final String STATE_ZOOM_ENABLED_CHANGE = "mapbox_zoomEnabledChange";
+ public static final String STATE_SCROLL_ENABLED = "mapbox_scrollEnabled";
+ public static final String STATE_SCROLL_ENABLED_CHANGE = "mapbox_scrollEnabledChange";
+ public static final String STATE_ROTATE_ENABLED = "mapbox_rotateEnabled";
+ public static final String STATE_ROTATE_ENABLED_CHANGE = "mapbox_rotateEnabledChange";
+ public static final String STATE_TILT_ENABLED = "mapbox_tiltEnabled";
+ public static final String STATE_TILT_ENABLED_CHANGE = "mapbox_tiltEnabledChange";
+ public static final String STATE_ZOOM_CONTROLS_ENABLED = "mapbox_zoomControlsEnabled";
+ public static final String STATE_DOUBLE_TAP_ENABLED = "mapbox_doubleTapEnabled";
+ public static final String STATE_DOUBLE_TAP_ENABLED_CHANGE = "mapbox_doubleTapEnabledChange";
+ public static final String STATE_DEBUG_ACTIVE = "mapbox_debugActive";
+ public static final String STATE_STYLE_URL = "mapbox_styleUrl";
+ public static final String STATE_MY_LOCATION_ENABLED = "mapbox_myLocationEnabled";
+ public static final String STATE_MY_LOCATION_TRACKING_MODE = "mapbox_myLocationTracking";
+ public static final String STATE_MY_BEARING_TRACKING_MODE = "mapbox_myBearingTracking";
+ public static final String STATE_MY_LOCATION_TRACKING_DISMISS = "mapbox_myLocationTrackingDismiss";
+ public static final String STATE_MY_BEARING_TRACKING_DISMISS = "mapbox_myBearingTrackingDismiss";
+ public static final String STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA = "mapbox_myBearingTrackingDismiss";
+ public static final String STATE_COMPASS_ENABLED = "mapbox_compassEnabled";
+ public static final String STATE_COMPASS_GRAVITY = "mapbox_compassGravity";
+ public static final String STATE_COMPASS_MARGIN_LEFT = "mapbox_compassMarginLeft";
+ public static final String STATE_COMPASS_MARGIN_TOP = "mapbox_compassMarginTop";
+ public static final String STATE_COMPASS_MARGIN_RIGHT = "mapbox_compassMarginRight";
+ public static final String STATE_COMPASS_MARGIN_BOTTOM = "mapbox_compassMarginBottom";
+ public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "mapbox_compassFade";
+ public static final String STATE_LOGO_GRAVITY = "mapbox_logoGravity";
+ public static final String STATE_LOGO_MARGIN_LEFT = "mapbox_logoMarginLeft";
+ public static final String STATE_LOGO_MARGIN_TOP = "mapbox_logoMarginTop";
+ public static final String STATE_LOGO_MARGIN_RIGHT = "mapbox_logoMarginRight";
+ public static final String STATE_LOGO_MARGIN_BOTTOM = "mapbox_logoMarginBottom";
+ public static final String STATE_LOGO_ENABLED = "mapbox_logoEnabled";
+ public static final String STATE_ATTRIBUTION_GRAVITY = "mapbox_attrGravity";
+ public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "mapbox_attrMarginLeft";
+ public static final String STATE_ATTRIBUTION_MARGIN_TOP = "mapbox_attrMarginTop";
+ public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "mapbox_attrMarginRight";
+ public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "mapbox_atrrMarginBottom";
+ public static final String STATE_ATTRIBUTION_ENABLED = "mapbox_atrrEnabled";
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
index cba2fb282c..f53c65d055 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
@@ -38,6 +38,6 @@ public class MyBearingTracking {
*/
public static final int GPS = 0x00000008;
- //public static final int COMBINED = 0x00000012;
+ // public static final int COMBINED = 0x00000012;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
index d1eaac04de..39f653596f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
@@ -34,4 +34,4 @@ public class MyLocationTracking {
*/
public static final int TRACKING_FOLLOW = 0x00000004;
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
index e5a647841f..bd24379af3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
@@ -7,4 +7,4 @@ public class InvalidMarkerPositionException extends RuntimeException {
+ "Missing the required position field. "
+ "Provide a non null LatLng as position to the Marker.");
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java
deleted file mode 100644
index e2e114fa77..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.mapbox.mapboxsdk.exceptions;
-
-import android.os.Bundle;
-
-import com.mapbox.mapboxsdk.maps.MapView;
-
-/**
- * A {@code TelemetryServiceNotConfiguredException} is thrown by {@link MapView} when it checks and finds that
- * TelemetryService has not been configured in the app's AndroidManifest.xml {@link MapView#onCreate(Bundle)}
- *
- * @see MapView#onCreate(Bundle)
- */
-public class TelemetryServiceNotConfiguredException extends RuntimeException {
-
- public TelemetryServiceNotConfiguredException() {
- super("\nTelemetryService is not configured in your applications AndroidManifest.xml. "
- + "\nPlease add \"com.mapbox.mapboxsdk.telemetry.TelemetryService\" service in your applications "
- + "AndroidManifest.xml"
- + "\nFor an example visit http://goo.gl/cET0Jn. For more information visit https://www.mapbox.com/android-sdk/.");
- }
-
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
index b18b7e87b0..5e3064f75f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
@@ -4,8 +4,8 @@ import android.location.Location;
import android.os.Parcel;
import android.os.Parcelable;
-import com.mapbox.mapboxsdk.constants.GeoConstants;
-import com.mapbox.mapboxsdk.utils.MathUtils;
+import com.mapbox.services.android.telemetry.constants.GeoConstants;
+import com.mapbox.services.android.telemetry.utils.MathUtils;
/**
* A geographical location which contains a single latitude, longitude pair, with
@@ -127,13 +127,8 @@ public class LatLng implements ILatLng, Parcelable {
* @return New LatLng object with wrapped Longitude
*/
public LatLng wrap() {
- LatLng wrappedVersion = new LatLng(this);
- double lon = wrappedVersion.getLongitude();
- if (lon < GeoConstants.MIN_LONGITUDE || lon > GeoConstants.MAX_LONGITUDE) {
- wrappedVersion.setLongitude(MathUtils.wrap(wrappedVersion.getLongitude(), GeoConstants.MIN_LONGITUDE,
- GeoConstants.MAX_LONGITUDE));
- }
- return wrappedVersion;
+ longitude = MathUtils.wrap(longitude, GeoConstants.MIN_LONGITUDE, GeoConstants.MAX_LONGITUDE);
+ return this;
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
index dd7fef4d23..d00ccdb9b8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
@@ -100,4 +100,4 @@ public class LatLngSpan implements Parcelable {
out.writeDouble(mLatitudeSpan);
out.writeDouble(mLongitudeSpan);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
index 45300f248c..c5b8ad3077 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
@@ -127,4 +127,4 @@ public class VisibleRegion implements Parcelable {
}
};
-} \ No newline at end of file
+}
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 2c6251638a..cedc5fe46c 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
@@ -123,7 +123,7 @@ class HTTPRequest implements Callback {
body = response.body().bytes();
} catch (IOException ioException) {
onFailure(ioException);
- //throw ioException;
+ // throw ioException;
return;
} finally {
response.body().close();
@@ -183,7 +183,7 @@ class HTTPRequest implements Callback {
return USER_AGENT_STRING = Util.toHumanReadableAscii(
String.format("%s %s (%s) Android/%s (%s)",
getApplicationIdentifier(),
- BuildConfig.MAPBOX_VERSION_STRING,
+ com.mapbox.services.android.telemetry.BuildConfig.MAPBOX_VERSION_STRING,
BuildConfig.GIT_REVISION_SHORT,
Build.VERSION.SDK_INT,
Build.CPU_ABI)
@@ -202,4 +202,4 @@ class HTTPRequest implements Callback {
return "";
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java
deleted file mode 100644
index 7d86d8b096..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.mapbox.mapboxsdk.location;
-
-import android.location.Location;
-
-/**
- * Callback interface for when a location change occurs.
- */
-public interface LocationListener {
-
- /**
- * Callback method for receiving location updates from LocationServices.
- *
- * @param location The new Location data
- */
- void onLocationChanged(Location location);
-
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
deleted file mode 100644
index aaf08c8b55..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.mapbox.mapboxsdk.location;
-
-import android.Manifest;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.location.Location;
-import android.location.LocationManager;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.content.LocalBroadcastManager;
-
-import timber.log.Timber;
-
-import com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver;
-import com.mapzen.android.lost.api.LocationRequest;
-import com.mapzen.android.lost.api.LostApiClient;
-
-import java.util.concurrent.CopyOnWriteArrayList;
-
-import static com.mapzen.android.lost.api.LocationServices.FusedLocationApi;
-
-/**
- * Manages locational updates. Contains methods to register and unregister location listeners.
- * <ul>
- * <li>You can register a {@link LocationListener} with {@link #addLocationListener(LocationListener)} to receive
- * location updates.</li>
- * <li> You can unregister a {@link LocationListener} with {@link #removeLocationListener(LocationListener)}.</li>
- * </ul>
- * <p>
- * Note: If registering a listener in your Activity.onStart() implementation, you should unregister it in
- * Activity.onStop(). (You won't receive location updates when paused, and this will cut down on unnecessary system
- * overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back
- * in the history stack.
- * </p>
- */
-public class LocationServices implements LostApiClient.ConnectionCallbacks,
- com.mapzen.android.lost.api.LocationListener {
-
- private static LocationServices instance;
-
- private Context context;
- private LostApiClient locationClient;
- private Location lastLocation;
-
- private CopyOnWriteArrayList<LocationListener> locationListeners;
-
- private boolean isGpsEnabled;
-
- /**
- * Private constructor for singleton LocationServices
- */
- private LocationServices(Context context) {
- super();
- this.context = context;
- // Setup location services
- locationClient = new LostApiClient.Builder(context).addConnectionCallbacks(this).build();
- locationListeners = new CopyOnWriteArrayList<>();
- }
-
- /**
- * Primary (singleton) access method for LocationServices
- *
- * @param context Context
- * @return LocationServices
- */
- public static LocationServices getLocationServices(@NonNull final Context context) {
- if (instance == null) {
- instance = new LocationServices(context.getApplicationContext());
- }
- return instance;
- }
-
- /**
- * Enabled / Disable GPS focused location tracking
- *
- * @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled
- */
- public void toggleGPS(boolean enableGPS) {
- if (!areLocationPermissionsGranted()) {
- Timber.w("Location Permissions Not Granted Yet. Try again after requesting.");
- return;
- }
-
- // Disconnect
- if (locationClient.isConnected()) {
- // Disconnect first to ensure that the new requests are GPS
- FusedLocationApi.removeLocationUpdates(locationClient, this);
- locationClient.disconnect();
- }
- isGpsEnabled = enableGPS;
-
- // Setup Fresh
- locationClient.connect();
- }
-
- @Override
- public void onConnected() {
- //noinspection MissingPermission
- Location lastLocation = FusedLocationApi.getLastLocation(locationClient);
- if (lastLocation != null) {
- this.lastLocation = lastLocation;
- }
-
- LocationRequest locationRequest;
-
- if (isGpsEnabled) {
- // LocationRequest Tuned for GPS
- locationRequest = LocationRequest.create()
- .setFastestInterval(1000)
- .setSmallestDisplacement(3.0f)
- .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
- //noinspection MissingPermission
- FusedLocationApi.requestLocationUpdates(locationClient, locationRequest, this);
- } else {
- // LocationRequest Tuned for PASSIVE
- locationRequest = LocationRequest.create()
- .setFastestInterval(1000)
- .setSmallestDisplacement(3.0f)
- .setPriority(LocationRequest.PRIORITY_NO_POWER);
- //noinspection MissingPermission
- FusedLocationApi.requestLocationUpdates(locationClient, locationRequest, this);
- }
- }
-
- @Override
- public void onConnectionSuspended() {
- }
-
- /**
- * Returns if the GPS sensor is currently enabled
- *
- * @return active state of the GPS
- */
- public boolean isGpsEnabled() {
- return isGpsEnabled;
- }
-
- /**
- * Called when the location has changed.
- *
- * @param location The updated location
- */
- @Override
- public void onLocationChanged(Location location) {
- // Timber.d("onLocationChanged()..." + location);
- this.lastLocation = location;
-
- // Update Listeners
- for (LocationListener listener : this.locationListeners) {
- listener.onLocationChanged(location);
- }
-
- // Update the Telemetry Receiver
- Intent locIntent = new Intent(TelemetryLocationReceiver.INTENT_STRING);
- locIntent.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
- LocalBroadcastManager.getInstance(context.getApplicationContext()).sendBroadcast(locIntent);
- }
-
- /**
- * Last known location
- *
- * @return Last known location data
- */
- public Location getLastLocation() {
- return lastLocation;
- }
-
- /**
- * Registers a LocationListener to receive location updates
- *
- * @param locationListener LocationListener
- */
- public void addLocationListener(@NonNull LocationListener locationListener) {
- if (!this.locationListeners.contains(locationListener)) {
- this.locationListeners.add(locationListener);
- }
- }
-
- /**
- * Unregister a LocationListener to stop receiving location updates
- *
- * @param locationListener LocationListener to remove
- * @return True if LocationListener was found and removed, False if it was not
- */
- public boolean removeLocationListener(@NonNull LocationListener locationListener) {
- return this.locationListeners.remove(locationListener);
- }
-
- /**
- * Check status of Location Permissions
- *
- * @return True if granted to the app, False if not
- */
- public boolean areLocationPermissionsGranted() {
- if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)
- && (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- Timber.w("Location Permissions Not Granted Yet. Try again after requesting.");
- return false;
- }
- return true;
- }
-
- @Override
- public void onProviderDisabled(String provider) {
- }
-
- @Override
- public void onProviderEnabled(String provider) {
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
new file mode 100644
index 0000000000..5a87f6384f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
@@ -0,0 +1,148 @@
+package com.mapbox.mapboxsdk.location;
+
+import android.content.Context;
+import android.location.Location;
+import android.util.Log;
+
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
+import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
+import com.mapzen.android.lost.api.LocationListener;
+import com.mapzen.android.lost.api.LocationRequest;
+import com.mapzen.android.lost.api.LocationServices;
+import com.mapzen.android.lost.api.LostApiClient;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Manages locational updates. Contains methods to register and unregister location listeners.
+ * <ul>
+ * <li>You can register a {@link LocationEngineListener} with
+ * {@link #addLocationEngineListener(LocationEngineListener)} to receive
+ * location updates.</li>
+ * <li> You can unregister a {@link LocationEngineListener} with
+ * {@link #removeLocationEngineListener(LocationEngineListener)} to stop receiving location updates.</li>
+ * </ul>
+ * <p>
+ * Note: If registering a listener in your Activity.onStart() implementation, you should unregister it in
+ * Activity.onStop(). (You won't receive location updates when paused, and this will cut down on unnecessary system
+ * overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back
+ * in the history stack.
+ * </p>
+ */
+public class LocationSource extends LocationEngine implements
+ LostApiClient.ConnectionCallbacks, LocationListener {
+
+ private static final String LOG_TAG = LocationSource.class.getSimpleName();
+
+ private static LocationEngine instance;
+
+ private WeakReference<Context> context;
+ private LostApiClient lostApiClient;
+
+ public LocationSource(Context context) {
+ super();
+ this.context = new WeakReference<>(context);
+ lostApiClient = new LostApiClient.Builder(this.context.get())
+ .addConnectionCallbacks(this)
+ .build();
+ }
+
+ public static synchronized LocationEngine getLocationEngine(Context context) {
+ if (instance == null) {
+ instance = new LocationSource(context.getApplicationContext());
+ }
+
+ return instance;
+ }
+
+ @Override
+ public void activate() {
+ if (lostApiClient != null && !lostApiClient.isConnected()) {
+ lostApiClient.connect();
+ }
+ }
+
+ @Override
+ public void deactivate() {
+ if (lostApiClient != null && lostApiClient.isConnected()) {
+ lostApiClient.disconnect();
+ }
+ }
+
+ @Override
+ public boolean isConnected() {
+ return lostApiClient.isConnected();
+ }
+
+ @Override
+ public void onConnected() {
+ for (LocationEngineListener listener : locationListeners) {
+ listener.onConnected();
+ }
+ }
+
+ @Override
+ public void onConnectionSuspended() {
+ Log.d(LOG_TAG, "Connection suspended.");
+ }
+
+ @Override
+ public Location getLastLocation() {
+ if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
+ //noinspection MissingPermission
+ return LocationServices.FusedLocationApi.getLastLocation(lostApiClient);
+ }
+
+ return null;
+ }
+
+ @Override
+ public void requestLocationUpdates() {
+ // Common params
+ LocationRequest request = LocationRequest.create()
+ .setFastestInterval(1000)
+ .setSmallestDisplacement(3.0f);
+
+ // Priority matching is straightforward
+ if (priority == LocationEnginePriority.NO_POWER) {
+ request.setPriority(LocationRequest.PRIORITY_NO_POWER);
+ } else if (priority == LocationEnginePriority.LOW_POWER) {
+ request.setPriority(LocationRequest.PRIORITY_LOW_POWER);
+ } else if (priority == LocationEnginePriority.BALANCED_POWER_ACCURACY) {
+ request.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
+ } else if (priority == LocationEnginePriority.HIGH_ACCURACY) {
+ request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
+ }
+
+ if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
+ //noinspection MissingPermission
+ LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this);
+ }
+ }
+
+ @Override
+ public void removeLocationUpdates() {
+ if (lostApiClient.isConnected()) {
+ LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, this);
+ }
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ for (LocationEngineListener listener : locationListeners) {
+ listener.onLocationChanged(location);
+ }
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ Log.d(LOG_TAG, "Provider disabled: " + provider);
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ Log.d(LOG_TAG, "Provider enabled: " + provider);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 05b37bc80d..0c77723354 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -194,7 +194,7 @@ class AnnotationManager {
if (ids != null) {
id = ids[i];
} else {
- //unit test
+ // unit test
id++;
}
m.setId(id);
@@ -359,6 +359,7 @@ class AnnotationManager {
return selectedMarkers;
}
+ @NonNull
List<Marker> getMarkersInRect(@NonNull RectF rectangle) {
// convert Rectangle to be density depedent
float pixelRatio = nativeMapView.getPixelRatio();
@@ -622,6 +623,7 @@ class AnnotationManager {
boolean onTap(PointF tapPoint, float screenDensity) {
float toleranceSides = 4 * screenDensity;
float toleranceTopBottom = 10 * screenDensity;
+ boolean handledDefaultClick = false;
RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides,
tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom,
@@ -631,7 +633,8 @@ class AnnotationManager {
List<Marker> nearbyMarkers = getMarkersInRect(tapRect);
long newSelectedMarkerId = -1;
- if (nearbyMarkers != null && nearbyMarkers.size() > 0) {
+ // find a Marker that isn't selected yet
+ if (nearbyMarkers.size() > 0) {
Collections.sort(nearbyMarkers);
for (Marker nearbyMarker : nearbyMarkers) {
boolean found = false;
@@ -647,6 +650,7 @@ class AnnotationManager {
}
}
+ // if unselected marker found
if (newSelectedMarkerId >= 0) {
List<Annotation> annotations = getAnnotations();
int count = annotations.size();
@@ -655,7 +659,6 @@ class AnnotationManager {
if (annotation instanceof Marker) {
if (annotation.getId() == newSelectedMarkerId) {
Marker marker = (Marker) annotation;
- boolean handledDefaultClick = false;
if (marker instanceof MarkerView) {
handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker);
@@ -679,6 +682,22 @@ class AnnotationManager {
}
}
}
+ } else if (nearbyMarkers.size() > 0) {
+ // we didn't find an unselected marker, check if we can close an already open markers
+ for (Marker nearbyMarker : nearbyMarkers) {
+ for (Marker selectedMarker : selectedMarkers) {
+ if (nearbyMarker.equals(selectedMarker)) {
+ if (onMarkerClickListener != null) {
+ // end developer has provided a custom click listener
+ handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
+ if (!handledDefaultClick) {
+ deselectMarker(nearbyMarker);
+ }
+ }
+ return true;
+ }
+ }
+ }
}
return false;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 11dee078ac..0f4d3197cc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.graphics.PointF;
+import android.location.Location;
import android.support.annotation.NonNull;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ScaleGestureDetectorCompat;
@@ -15,8 +16,11 @@ import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.ShoveGestureDetector;
import com.almeros.android.multitouch.gesturedetectors.TwoFingerGestureDetector;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.telemetry.MapboxEvent;
-import com.mapbox.mapboxsdk.utils.MathUtils;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.services.android.telemetry.MapboxEvent;
+import com.mapbox.services.android.telemetry.MapboxTelemetry;
+import com.mapbox.services.android.telemetry.utils.MathUtils;
+import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
/**
* Manages gestures events on a MapView.
@@ -88,6 +92,18 @@ final class MapGestureDetector {
this.focalPoint = focalPoint;
}
+ /**
+ * Given coordinates from a gesture, use the current projection to translate it into
+ * a Location object.
+ *
+ * @param x coordinate
+ * @param y coordinate
+ * @return location
+ */
+ private Location getLocationFromGesture(float x, float y) {
+ LatLng latLng = projection.fromScreenLocation(new PointF(x, y));
+ return TelemetryUtils.buildLocation(latLng.getLongitude(), latLng.getLatitude());
+ }
/**
* Called when user touches the screen, all positions are absolute.
@@ -123,8 +139,9 @@ final class MapGestureDetector {
&& uiSettings.isZoomGesturesEnabled();
if (twoTap) {
// Confirmed 2nd Finger Down
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(event.getX(), event.getY()),
+ MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, transform.getZoom()));
}
break;
@@ -153,7 +170,8 @@ final class MapGestureDetector {
// Scroll / Pan Has Stopped
if (scrollInProgress) {
- MapboxEvent.trackGestureDragEndEvent(projection, event.getX(), event.getY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapDragEndEvent(
+ getLocationFromGesture(event.getX(), event.getY()), transform.getZoom()));
scrollInProgress = false;
}
@@ -181,7 +199,7 @@ final class MapGestureDetector {
*/
boolean onGenericMotionEvent(MotionEvent event) {
// Mouse events
- //if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18
+ // if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { // this is not available before API 18
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == InputDevice.SOURCE_CLASS_POINTER) {
// Choose the action
switch (event.getActionMasked()) {
@@ -225,7 +243,7 @@ final class MapGestureDetector {
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
- if (!uiSettings.isZoomGesturesEnabled()) {
+ if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled()) {
return false;
}
@@ -252,7 +270,9 @@ final class MapGestureDetector {
break;
}
- MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(e.getX(), e.getY()),
+ MapboxEvent.GESTURE_DOUBLETAP, transform.getZoom()));
return true;
}
@@ -281,8 +301,10 @@ final class MapGestureDetector {
}
}
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(motionEvent.getX(), motionEvent.getY()),
+ MapboxEvent.GESTURE_SINGLETAP, transform.getZoom()));
+
return true;
}
@@ -333,9 +355,6 @@ final class MapGestureDetector {
if (onFlingListener != null) {
onFlingListener.onFling();
}
-
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY(), transform.getZoom());
return true;
}
@@ -344,6 +363,9 @@ final class MapGestureDetector {
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (!scrollInProgress) {
scrollInProgress = true;
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(e1.getX(), e1.getY()),
+ MapboxEvent.GESTURE_PAN_START, transform.getZoom()));
}
if (!trackingSettings.isScrollGestureCurrentlyEnabled()) {
return false;
@@ -385,8 +407,9 @@ final class MapGestureDetector {
scaleGestureOccurred = true;
beginTime = detector.getEventTime();
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
+ MapboxEvent.GESTURE_PINCH_START, transform.getZoom()));
return true;
}
@@ -476,8 +499,9 @@ final class MapGestureDetector {
}
beginTime = detector.getEventTime();
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
+ MapboxEvent.GESTURE_ROTATION_START, transform.getZoom()));
return true;
}
@@ -556,8 +580,9 @@ final class MapGestureDetector {
}
beginTime = detector.getEventTime();
- MapboxEvent.trackGestureEvent(projection,
- MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom());
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapClickEvent(
+ getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
+ MapboxEvent.GESTURE_PITCH_START, transform.getZoom()));
return true;
}
@@ -654,4 +679,4 @@ final class MapGestureDetector {
void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
-} \ No newline at end of file
+}
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 3cb074d209..16b7bf1800 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
@@ -3,25 +3,21 @@ package com.mapbox.mapboxsdk.maps;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.SurfaceTexture;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.support.annotation.CallSuper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v7.app.AlertDialog;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -45,8 +41,9 @@ import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
-import com.mapbox.mapboxsdk.telemetry.MapboxEvent;
-import com.mapbox.mapboxsdk.telemetry.MapboxEventManager;
+import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import com.mapbox.services.android.telemetry.MapboxEvent;
+import com.mapbox.services.android.telemetry.MapboxTelemetry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,7 +69,7 @@ public class MapView extends FrameLayout {
private NativeMapView nativeMapView;
private boolean destroyed;
- private boolean hasSurface = false;
+ private boolean hasSurface;
private MapboxMap mapboxMap;
private MapCallback mapCallback;
@@ -83,8 +80,6 @@ public class MapView extends FrameLayout {
private MapKeyListener mapKeyListener;
private MapZoomButtonController mapZoomButtonController;
- private ConnectivityReceiver connectivityReceiver;
-
@UiThread
public MapView(@NonNull Context context) {
super(context);
@@ -106,7 +101,7 @@ public class MapView extends FrameLayout {
@UiThread
public MapView(@NonNull Context context, @Nullable MapboxMapOptions options) {
super(context);
- initialise(context, options);
+ initialise(context, options == null ? MapboxMapOptions.createFromAttributes(context, null) : options);
}
private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) {
@@ -127,15 +122,18 @@ public class MapView extends FrameLayout {
nativeMapView = new NativeMapView(this);
// callback for focal point invalidation
- FocalPointInvalidator focalPoint = new FocalPointInvalidator();
+ FocalPointInvalidator focalPoint = new FocalPointInvalidator(compassView);
// callback for registering touch listeners
RegisterTouchListener registerTouchListener = new RegisterTouchListener();
+ // callback for zooming in the camera
+ CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
+
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
- TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint);
+ TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator);
MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
AnnotationManager annotations = new AnnotationManager(nativeMapView, this, markerViewManager);
@@ -164,7 +162,7 @@ public class MapView extends FrameLayout {
setWillNotDraw(false);
// notify Map object about current connectivity state
- nativeMapView.setReachability(isConnected());
+ nativeMapView.setReachability(ConnectivityReceiver.instance(context).isConnected(context));
// initialise MapboxMap
mapboxMap.initialise(context, options);
@@ -199,10 +197,8 @@ public class MapView extends FrameLayout {
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
-
if (savedInstanceState == null) {
- MapboxEvent.trackMapLoadEvent();
+ MapboxTelemetry.getInstance().pushEvent(MapboxEvent.buildMapLoadEvent());
} else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
mapboxMap.onRestoreInstanceState(savedInstanceState);
}
@@ -234,7 +230,7 @@ public class MapView extends FrameLayout {
public void onStart() {
onStartCalled = true;
mapboxMap.onStart();
- registerConnectivityReceiver();
+ ConnectivityReceiver.instance(getContext()).activate();
}
/**
@@ -264,7 +260,7 @@ public class MapView extends FrameLayout {
public void onStop() {
onStopCalled = true;
mapboxMap.onStop();
- unregisterConnectivityReceiver();
+ ConnectivityReceiver.instance(getContext()).deactivate();
}
/**
@@ -286,18 +282,6 @@ public class MapView extends FrameLayout {
nativeMapView = null;
}
- private void registerConnectivityReceiver() {
- getContext().registerReceiver(connectivityReceiver = new ConnectivityReceiver(),
- new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
- }
-
- private void unregisterConnectivityReceiver() {
- if (connectivityReceiver != null) {
- getContext().unregisterReceiver(connectivityReceiver);
- connectivityReceiver = null;
- }
- }
-
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
@@ -405,11 +389,6 @@ public class MapView extends FrameLayout {
return;
}
- // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
- if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
- }
-
nativeMapView.setStyleUrl(url);
}
@@ -552,30 +531,6 @@ public class MapView extends FrameLayout {
}
//
- // Connectivity events
- //
-
- // This class handles connectivity changes
- private class ConnectivityReceiver extends BroadcastReceiver {
-
- // Called when an action we are listening to in the manifest has been sent
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!destroyed && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- nativeMapView.setReachability(!intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false));
- }
- }
- }
-
- // Called when MapView is being created
- private boolean isConnected() {
- ConnectivityManager connectivityManager = (ConnectivityManager)
- getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
- return (activeNetwork != null) && activeNetwork.isConnectedOrConnecting();
- }
-
- //
// Map events
//
@@ -663,7 +618,7 @@ public class MapView extends FrameLayout {
builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(true);
+ MapboxTelemetry.getInstance().setTelemetryEnabled(true);
dialog.cancel();
}
});
@@ -680,7 +635,7 @@ public class MapView extends FrameLayout {
builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(false);
+ MapboxTelemetry.getInstance().setTelemetryEnabled(false);
dialog.cancel();
}
});
@@ -941,9 +896,18 @@ public class MapView extends FrameLayout {
private class FocalPointInvalidator implements FocalPointChangeListener {
+ private final FocalPointChangeListener[] focalPointChangeListeners;
+
+ FocalPointInvalidator(FocalPointChangeListener... listeners) {
+ focalPointChangeListeners = listeners;
+ }
+
@Override
public void onFocalPointChanged(PointF pointF) {
mapGestureDetector.setFocalPoint(pointF);
+ for (FocalPointChangeListener focalPointChangeListener : focalPointChangeListeners) {
+ focalPointChangeListener.onFocalPointChanged(pointF);
+ }
}
}
@@ -970,6 +934,16 @@ public class MapView extends FrameLayout {
}
}
+ private class CameraZoomInvalidator implements TrackingSettings.CameraZoomInvalidator {
+ @Override
+ public void zoomTo(double zoomLevel) {
+ double currentZoomLevel = mapboxMap.getCameraPosition().zoom;
+ if (currentZoomLevel < zoomLevel) {
+ mapboxMap.getTransform().setZoom(zoomLevel);
+ }
+ }
+ }
+
private static class MapCallback implements OnMapChangedListener {
private final MapboxMap mapboxMap;
@@ -984,9 +958,14 @@ public class MapView extends FrameLayout {
public void onMapChanged(@MapChange int change) {
if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
initialLoad = false;
- mapboxMap.onPreMapReady();
- onMapReady();
- mapboxMap.onPostMapReady();
+ new Handler().post(new Runnable() {
+ @Override
+ public void run() {
+ mapboxMap.onPreMapReady();
+ onMapReady();
+ mapboxMap.onPostMapReady();
+ }
+ });
} else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
mapboxMap.onUpdate();
}
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 9e8073edb8..e3e33ec067 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
@@ -8,6 +8,7 @@ import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
@@ -16,7 +17,6 @@ import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
-import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
@@ -38,8 +38,6 @@ import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Layer;
-import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
-import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -212,6 +210,22 @@ public final class MapboxMap {
nativeMapView.setTransitionDelay(delay);
}
+ /**
+ * Retrieve all the layers in the style
+ *
+ * @return all the layers in the current style
+ */
+ @UiThread
+ public List<Layer> getLayers() {
+ return nativeMapView.getLayers();
+ }
+
+ /**
+ * Get the layer by id
+ *
+ * @param layerId the layer's id
+ * @return the layer, if present in the style
+ */
@Nullable
@UiThread
public Layer getLayer(@NonNull String layerId) {
@@ -229,7 +243,7 @@ public final class MapboxMap {
@UiThread
public <T extends Layer> T getLayerAs(@NonNull String layerId) {
try {
- //noinspection unchecked
+ // noinspection unchecked
return (T) nativeMapView.getLayer(layerId);
} catch (ClassCastException exception) {
Timber.e(String.format("Layer: %s is a different type: %s", layerId, exception));
@@ -244,42 +258,95 @@ public final class MapboxMap {
*/
@UiThread
public void addLayer(@NonNull Layer layer) {
- addLayer(layer, null);
+ nativeMapView.addLayer(layer);
+ }
+
+ /**
+ * Adds the layer to the map. The layer must be newly created and not added to the map before
+ *
+ * @param layer the layer to add
+ * @param below the layer id to add this layer before
+ */
+ @UiThread
+ public void addLayerBelow(@NonNull Layer layer, @NonNull String below) {
+ nativeMapView.addLayerBelow(layer, below);
}
/**
* Adds the layer to the map. The layer must be newly created and not added to the map before
*
- * @param layer the layer to add
- * @param before the layer id to add this layer before
+ * @param layer the layer to add
+ * @param above the layer id to add this layer above
*/
@UiThread
- public void addLayer(@NonNull Layer layer, String before) {
- nativeMapView.addLayer(layer, before);
+ public void addLayerAbove(@NonNull Layer layer, @NonNull String above) {
+ nativeMapView.addLayerAbove(layer, above);
+ }
+
+ /**
+ * Adds the layer to the map at the specified index. The layer must be newly
+ * created and not added to the map before
+ *
+ * @param layer the layer to add
+ * @param index the index to insert the layer at
+ */
+ @UiThread
+ public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) {
+ nativeMapView.addLayerAt(layer, index);
}
/**
* Removes the layer. Any references to the layer become invalid and should not be used anymore
*
* @param layerId the layer to remove
- * @throws NoSuchLayerException the exception thrown when layer with layerId doesn't exist
+ * @return the removed layer or null if not found
*/
@UiThread
- public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
- nativeMapView.removeLayer(layerId);
+ @Nullable
+ public Layer removeLayer(@NonNull String layerId) {
+ return nativeMapView.removeLayer(layerId);
}
/**
* Removes the layer. The reference is re-usable after this and can be re-added
*
* @param layer the layer to remove
- * @throws NoSuchLayerException the exeption thrown when the layer doesn't exist
+ * @return the layer
*/
@UiThread
- public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException {
- nativeMapView.removeLayer(layer);
+ @Nullable
+ public Layer removeLayer(@NonNull Layer layer) {
+ return nativeMapView.removeLayer(layer);
}
+ /**
+ * Removes the layer. Any other references to the layer become invalid and should not be used anymore
+ *
+ * @param index the layer index
+ * @return the removed layer or null if not found
+ */
+ @UiThread
+ @Nullable
+ public Layer removeLayerAt(@IntRange(from = 0) int index) {
+ return nativeMapView.removeLayerAt(index);
+ }
+
+ /**
+ * Retrieve all the sources in the style
+ *
+ * @return all the sources in the current style
+ */
+ @UiThread
+ public List<Source> getSources() {
+ return nativeMapView.getSources();
+ }
+
+ /**
+ * Retrieve a source by id
+ *
+ * @param sourceId the source's id
+ * @return the source if present in the current style
+ */
@Nullable
@UiThread
public Source getSource(@NonNull String sourceId) {
@@ -297,7 +364,7 @@ public final class MapboxMap {
@UiThread
public <T extends Source> T getSourceAs(@NonNull String sourceId) {
try {
- //noinspection unchecked
+ // noinspection unchecked
return (T) nativeMapView.getSource(sourceId);
} catch (ClassCastException exception) {
Timber.e(String.format("Source: %s is a different type: %s", sourceId, exception));
@@ -319,22 +386,24 @@ public final class MapboxMap {
* Removes the source. Any references to the source become invalid and should not be used anymore
*
* @param sourceId the source to remove
- * @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist
+ * @return the source handle or null if the source was not present
*/
@UiThread
- public void removeSource(@NonNull String sourceId) throws NoSuchSourceException {
- nativeMapView.removeSource(sourceId);
+ @Nullable
+ public Source removeSource(@NonNull String sourceId) {
+ return nativeMapView.removeSource(sourceId);
}
/**
* Removes the source, preserving the reverence for re-use
*
* @param source the source to remove
- * @throws NoSuchSourceException the exception thrown when the source with sourceId doesn't exist
+ * @return the source
*/
@UiThread
- public void removeSource(@NonNull Source source) throws NoSuchSourceException {
- nativeMapView.removeSource(source);
+ @Nullable
+ public Source removeSource(@NonNull Source source) {
+ return nativeMapView.removeSource(source);
}
/**
@@ -515,9 +584,6 @@ public final class MapboxMap {
@UiThread
public final void moveCamera(CameraUpdate update) {
moveCamera(update, null);
- // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
- // invalidate camera position to provide OnCameraChange event.
- invalidateCameraPosition();
}
/**
@@ -534,6 +600,9 @@ public final class MapboxMap {
@Override
public void run() {
transform.moveCamera(MapboxMap.this, update, callback);
+ // MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
+ // invalidate camera position to provide OnCameraChange event.
+ invalidateCameraPosition();
}
});
}
@@ -615,7 +684,9 @@ public final class MapboxMap {
* easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
* will return the current location of the camera in flight.
* <p>
- * Note that this will cancel location tracking mode if enabled.
+ * Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling
+ * {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this
+ * method and calling it with true in the {@link CancelableCallback#onFinish()}.
* </p>
*
* @param update The change that should be applied to the camera.
@@ -629,39 +700,12 @@ public final class MapboxMap {
* Do not update or ease the camera from within onCancel().
*/
@UiThread
- public final void easeCamera(
- CameraUpdate update, int durationMs, boolean easingInterpolator, final MapboxMap.CancelableCallback callback) {
- // dismiss tracking, moving camera is equal to a gesture
- easeCamera(update, durationMs, easingInterpolator, true, callback);
- }
-
- /**
- * Gradually move the camera by a specified duration in milliseconds, zoom will not be affected
- * unless specified within {@link CameraUpdate}. A callback can be used to be notified when
- * easing the camera stops. If {@link #getCameraPosition()} is called during the animation, it
- * will return the current location of the camera in flight.
- * <p>
- * Note that this will cancel location tracking mode if enabled.
- * </p>
- *
- * @param update The change that should be applied to the camera.
- * @param durationMs The duration of the animation in milliseconds. This must be strictly
- * positive, otherwise an IllegalArgumentException will be thrown.
- * @param resetTrackingMode True to reset tracking modes if required, false to ignore
- * @param easingInterpolator True for easing interpolator, false for linear.
- * @param callback An optional callback to be notified from the main thread when the animation
- * stops. If the animation stops due to its natural completion, the callback
- * will be notified with onFinish(). If the animation stops due to interruption
- * by a later camera movement or a user gesture, onCancel() will be called.
- * Do not update or ease the camera from within onCancel().
- */
- @UiThread
public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
- final boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
+ final MapboxMap.CancelableCallback callback) {
new Handler().post(new Runnable() {
@Override
public void run() {
- transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, resetTrackingMode, callback);
+ transform.easeCamera(MapboxMap.this, update, durationMs, easingInterpolator, callback);
}
});
}
@@ -763,6 +807,21 @@ public final class MapboxMap {
transform.resetNorth();
}
+ /**
+ * Set focal bearing.
+ */
+ public void setFocalBearing(double bearing, float focalX, float focalY, long duration) {
+ transform.setBearing(bearing, focalX, focalY, duration);
+ }
+
+ public float getHeight() {
+ return nativeMapView.getHeight();
+ }
+
+ public float getWidth() {
+ return nativeMapView.getWidth();
+ }
+
//
// Debug
//
@@ -882,10 +941,6 @@ public final class MapboxMap {
private void setStyleUrl(@NonNull MapboxMapOptions options) {
String style = options.getStyle();
if (!TextUtils.isEmpty(style)) {
- // stopgap for https://github.com/mapbox/mapbox-gl-native/issues/6242
- if (TextUtils.isEmpty(nativeMapView.getAccessToken())) {
- nativeMapView.setAccessToken(Mapbox.getAccessToken());
- }
setStyleUrl(style);
}
}
@@ -1604,18 +1659,8 @@ public final class MapboxMap {
* @param bitmap A pre-allocated bitmap.
*/
@UiThread
- public void snapshot(@NonNull SnapshotReadyCallback callback, @Nullable final Bitmap bitmap) {
- nativeMapView.addSnapshotCallback(callback, bitmap);
- }
-
- /**
- * Takes a snapshot of the map.
- *
- * @param callback Callback method invoked when the snapshot is taken.
- */
- @UiThread
public void snapshot(@NonNull SnapshotReadyCallback callback) {
- snapshot(callback, null);
+ nativeMapView.addSnapshotCallback(callback);
}
/**
@@ -2032,4 +2077,4 @@ public final class MapboxMap {
Transform getTransform() {
return transform;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index 518ef47329..6467033ead 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -66,6 +66,7 @@ public class MapboxMapOptions implements Parcelable {
private boolean tiltGesturesEnabled = true;
private boolean zoomGesturesEnabled = true;
private boolean zoomControlsEnabled = false;
+ private boolean doubleTapGesturesEnabled = true;
private boolean myLocationEnabled;
private Drawable myLocationForegroundDrawable;
@@ -116,6 +117,7 @@ public class MapboxMapOptions implements Parcelable {
tiltGesturesEnabled = in.readByte() != 0;
zoomControlsEnabled = in.readByte() != 0;
zoomGesturesEnabled = in.readByte() != 0;
+ doubleTapGesturesEnabled = in.readByte() != 0;
myLocationEnabled = in.readByte() != 0;
@@ -184,6 +186,8 @@ public class MapboxMapOptions implements Parcelable {
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiTiltGestures, true));
mapboxMapOptions.zoomControlsEnabled(
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiZoomControls, false));
+ mapboxMapOptions.doubleTapGesturesEnabled(
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiDoubleTapGestures, true));
mapboxMapOptions.maxZoomPreference(typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoomMax,
MapboxConstants.MAXIMUM_ZOOM));
@@ -529,6 +533,17 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Specifies if the double tap gesture is enabled for a map view.
+ *
+ * @param enabled True and gesture will be enabled
+ * @return This
+ */
+ public MapboxMapOptions doubleTapGesturesEnabled(boolean enabled) {
+ doubleTapGesturesEnabled = enabled;
+ return this;
+ }
+
+ /**
* Specifies if the user location view is enabled for a map view.
*
* @param locationEnabled True and gesture will be enabled
@@ -809,6 +824,15 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Get the current configured double tap gesture state for a map view.
+ *
+ * @return True indicates gesture is enabled
+ */
+ public boolean getDoubleTapGesturesEnabled() {
+ return doubleTapGesturesEnabled;
+ }
+
+ /**
* Get the current configured visibility state for attribution for a map view.
*
* @return Visibility state of the attribution
@@ -987,6 +1011,7 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (tiltGesturesEnabled ? 1 : 0));
dest.writeByte((byte) (zoomControlsEnabled ? 1 : 0));
dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0));
+ dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0));
dest.writeByte((byte) (myLocationEnabled ? 1 : 0));
@@ -1066,6 +1091,9 @@ public class MapboxMapOptions implements Parcelable {
if (zoomControlsEnabled != options.zoomControlsEnabled) {
return false;
}
+ if (doubleTapGesturesEnabled != options.doubleTapGesturesEnabled) {
+ return false;
+ }
if (myLocationEnabled != options.myLocationEnabled) {
return false;
}
@@ -1146,6 +1174,7 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + (tiltGesturesEnabled ? 1 : 0);
result = 31 * result + (zoomGesturesEnabled ? 1 : 0);
result = 31 * result + (zoomControlsEnabled ? 1 : 0);
+ result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0);
result = 31 * result + (myLocationEnabled ? 1 : 0);
result = 31 * result + (myLocationForegroundDrawable != null ? myLocationForegroundDrawable.hashCode() : 0);
result = 31 * result + (myLocationForegroundBearingDrawable != null
@@ -1161,4 +1190,4 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + (style != null ? style.hashCode() : 0);
return result;
}
-} \ No newline at end of file
+}
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 0c15480dee..e02a0f3d36 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
@@ -3,10 +3,10 @@ package com.mapbox.mapboxsdk.maps;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
+import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
@@ -20,10 +20,10 @@ import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
-import com.mapbox.mapboxsdk.offline.OfflineManager;
+import com.mapbox.mapboxsdk.storage.FileSource;
+import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Layer;
-import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
-import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException;
+import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.commons.geojson.Feature;
@@ -35,6 +35,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import timber.log.Timber;
+
// Class that wraps the native methods for convenience
final class NativeMapView {
@@ -42,11 +43,14 @@ final class NativeMapView {
private boolean destroyed = false;
// Holds the pointer to JNI NativeMapView
- private long nativeMapViewPtr = 0;
+ private long nativePtr = 0;
// Used for callbacks
private MapView mapView;
+ //Hold a reference to prevent it from being GC'd as long as it's used on the native side
+ private final FileSource fileSource;
+
// Device density
private final float pixelRatio;
@@ -54,7 +58,7 @@ final class NativeMapView {
private CopyOnWriteArrayList<MapView.OnMapChangedListener> onMapChangedListeners;
// Listener invoked to return a bitmap of the map
- private SnapshotRequest snapshotRequest;
+ private MapboxMap.SnapshotReadyCallback snapshotReadyCallback;
//
// Static methods
@@ -70,15 +74,9 @@ final class NativeMapView {
public NativeMapView(MapView mapView) {
Context context = mapView.getContext();
- String dataPath = OfflineManager.getDatabasePath(context);
-
- // With the availability of offline, we're unifying the ambient (cache) and the offline
- // databases to be in the same folder, outside cache, to avoid automatic deletion from
- // the system
- String cachePath = dataPath;
+ fileSource = FileSource.getInstance(context);
pixelRatio = context.getResources().getDisplayMetrics().density;
- String apkPath = context.getPackageCodePath();
int availableProcessors = Runtime.getRuntime().availableProcessors();
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -97,7 +95,8 @@ final class NativeMapView {
}
onMapChangedListeners = new CopyOnWriteArrayList<>();
this.mapView = mapView;
- nativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
+
+ nativeInitialize(this, fileSource, pixelRatio, availableProcessors, totalMemory);
}
//
@@ -114,8 +113,7 @@ final class NativeMapView {
}
public void destroy() {
- nativeDestroy(nativeMapViewPtr);
- nativeMapViewPtr = 0;
+ nativeDestroy();
mapView = null;
destroyed = true;
}
@@ -124,56 +122,56 @@ final class NativeMapView {
if (isDestroyedOn("initializeDisplay")) {
return;
}
- nativeInitializeDisplay(nativeMapViewPtr);
+ nativeInitializeDisplay();
}
public void terminateDisplay() {
if (isDestroyedOn("terminateDisplay")) {
return;
}
- nativeTerminateDisplay(nativeMapViewPtr);
+ nativeTerminateDisplay();
}
public void initializeContext() {
if (isDestroyedOn("initializeContext")) {
return;
}
- nativeInitializeContext(nativeMapViewPtr);
+ nativeInitializeContext();
}
public void terminateContext() {
if (isDestroyedOn("terminateContext")) {
return;
}
- nativeTerminateContext(nativeMapViewPtr);
+ nativeTerminateContext();
}
public void createSurface(Surface surface) {
if (isDestroyedOn("createSurface")) {
return;
}
- nativeCreateSurface(nativeMapViewPtr, surface);
+ nativeCreateSurface(surface);
}
public void destroySurface() {
if (isDestroyedOn("destroySurface")) {
return;
}
- nativeDestroySurface(nativeMapViewPtr);
+ nativeDestroySurface();
}
public void update() {
if (isDestroyedOn("update")) {
return;
}
- nativeUpdate(nativeMapViewPtr);
+ nativeUpdate();
}
public void render() {
if (isDestroyedOn("render")) {
return;
}
- nativeRender(nativeMapViewPtr);
+ nativeRender();
}
public void resizeView(int width, int height) {
@@ -204,7 +202,7 @@ final class NativeMapView {
+ "capping value at 65535 instead of " + height);
height = 65535;
}
- nativeViewResize(nativeMapViewPtr, width, height);
+ nativeResizeView(width, height);
}
public void resizeFramebuffer(int fbWidth, int fbHeight) {
@@ -228,98 +226,49 @@ final class NativeMapView {
throw new IllegalArgumentException(
"fbHeight cannot be greater than 65535.");
}
- nativeFramebufferResize(nativeMapViewPtr, fbWidth, fbHeight);
- }
-
- public void addClass(String clazz) {
- if (isDestroyedOn("addClass")) {
- return;
- }
- nativeAddClass(nativeMapViewPtr, clazz);
- }
-
- public void removeClass(String clazz) {
- if (isDestroyedOn("removeClass")) {
- return;
- }
- nativeRemoveClass(nativeMapViewPtr, clazz);
- }
-
- public boolean hasClass(String clazz) {
- if (isDestroyedOn("hasClass")) {
- return false;
- }
- return nativeHasClass(nativeMapViewPtr, clazz);
- }
-
- public void setClasses(List<String> classes) {
- if (isDestroyedOn("setClasses")) {
- return;
- }
- nativeSetClasses(nativeMapViewPtr, classes);
- }
-
- public List<String> getClasses() {
- if (isDestroyedOn("getClasses")) {
- return new ArrayList<>();
- }
- return nativeGetClasses(nativeMapViewPtr);
+ nativeResizeFramebuffer(fbWidth, fbHeight);
}
public void setStyleUrl(String url) {
if (isDestroyedOn("setStyleUrl")) {
return;
}
- nativeSetStyleUrl(nativeMapViewPtr, url);
+ nativeSetStyleUrl(url);
}
public String getStyleUrl() {
if (isDestroyedOn("getStyleUrl")) {
return null;
}
- return nativeGetStyleUrl(nativeMapViewPtr);
+ return nativeGetStyleUrl();
}
public void setStyleJson(String newStyleJson) {
if (isDestroyedOn("setStyleJson")) {
return;
}
- nativeSetStyleJson(nativeMapViewPtr, newStyleJson);
+ nativeSetStyleJson(newStyleJson);
}
public String getStyleJson() {
if (isDestroyedOn("getStyleJson")) {
return null;
}
- return nativeGetStyleJson(nativeMapViewPtr);
- }
-
- public void setAccessToken(String accessToken) {
- if (isDestroyedOn("setAccessToken")) {
- return;
- }
- nativeSetAccessToken(nativeMapViewPtr, accessToken);
- }
-
- public String getAccessToken() {
- if (isDestroyedOn("getAccessToken")) {
- return null;
- }
- return nativeGetAccessToken(nativeMapViewPtr);
+ return nativeGetStyleJson();
}
public void cancelTransitions() {
if (isDestroyedOn("cancelTransitions")) {
return;
}
- nativeCancelTransitions(nativeMapViewPtr);
+ nativeCancelTransitions();
}
public void setGestureInProgress(boolean inProgress) {
if (isDestroyedOn("setGestureInProgress")) {
return;
}
- nativeSetGestureInProgress(nativeMapViewPtr, inProgress);
+ nativeSetGestureInProgress(inProgress);
}
public void moveBy(double dx, double dy) {
@@ -333,7 +282,7 @@ final class NativeMapView {
if (isDestroyedOn("moveBy")) {
return;
}
- nativeMoveBy(nativeMapViewPtr, dx / pixelRatio, dy / pixelRatio, duration);
+ nativeMoveBy(dx / pixelRatio, dy / pixelRatio, duration);
}
public void setLatLng(LatLng latLng) {
@@ -347,35 +296,36 @@ final class NativeMapView {
if (isDestroyedOn("setLatLng")) {
return;
}
- nativeSetLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude(), duration);
+ nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration);
}
public LatLng getLatLng() {
if (isDestroyedOn("")) {
return new LatLng();
}
- return nativeGetLatLng(nativeMapViewPtr);
+ // wrap longitude values coming from core
+ return nativeGetLatLng().wrap();
}
public void resetPosition() {
if (isDestroyedOn("resetPosition")) {
return;
}
- nativeResetPosition(nativeMapViewPtr);
+ nativeResetPosition();
}
public double getPitch() {
if (isDestroyedOn("getPitch")) {
return 0;
}
- return nativeGetPitch(nativeMapViewPtr);
+ return nativeGetPitch();
}
public void setPitch(double pitch, long duration) {
if (isDestroyedOn("setPitch")) {
return;
}
- nativeSetPitch(nativeMapViewPtr, pitch, duration);
+ nativeSetPitch(pitch, duration);
}
public void scaleBy(double ds) {
@@ -396,7 +346,7 @@ final class NativeMapView {
if (isDestroyedOn("scaleBy")) {
return;
}
- nativeScaleBy(nativeMapViewPtr, ds, cx / pixelRatio, cy / pixelRatio, duration);
+ nativeScaleBy(ds, cx / pixelRatio, cy / pixelRatio, duration);
}
public void setScale(double scale) {
@@ -417,14 +367,14 @@ final class NativeMapView {
if (isDestroyedOn("setScale")) {
return;
}
- nativeSetScale(nativeMapViewPtr, scale, cx / pixelRatio, cy / pixelRatio, duration);
+ nativeSetScale(scale, cx / pixelRatio, cy / pixelRatio, duration);
}
public double getScale() {
if (isDestroyedOn("getScale")) {
return 0;
}
- return nativeGetScale(nativeMapViewPtr);
+ return nativeGetScale();
}
public void setZoom(double zoom) {
@@ -438,49 +388,49 @@ final class NativeMapView {
if (isDestroyedOn("setZoom")) {
return;
}
- nativeSetZoom(nativeMapViewPtr, zoom, duration);
+ nativeSetZoom(zoom, duration);
}
public double getZoom() {
if (isDestroyedOn("getZoom")) {
return 0;
}
- return nativeGetZoom(nativeMapViewPtr);
+ return nativeGetZoom();
}
public void resetZoom() {
if (isDestroyedOn("resetZoom")) {
return;
}
- nativeResetZoom(nativeMapViewPtr);
+ nativeResetZoom();
}
public void setMinZoom(double zoom) {
if (isDestroyedOn("setMinZoom")) {
return;
}
- nativeSetMinZoom(nativeMapViewPtr, zoom);
+ nativeSetMinZoom(zoom);
}
public double getMinZoom() {
if (isDestroyedOn("getMinZoom")) {
return 0;
}
- return nativeGetMinZoom(nativeMapViewPtr);
+ return nativeGetMinZoom();
}
public void setMaxZoom(double zoom) {
if (isDestroyedOn("setMaxZoom")) {
return;
}
- nativeSetMaxZoom(nativeMapViewPtr, zoom);
+ nativeSetMaxZoom(zoom);
}
public double getMaxZoom() {
if (isDestroyedOn("getMaxZoom")) {
return 0;
}
- return nativeGetMaxZoom(nativeMapViewPtr);
+ return nativeGetMaxZoom();
}
public void rotateBy(double sx, double sy, double ex, double ey) {
@@ -495,14 +445,14 @@ final class NativeMapView {
if (isDestroyedOn("rotateBy")) {
return;
}
- nativeRotateBy(nativeMapViewPtr, sx / pixelRatio, sy / pixelRatio, ex, ey, duration);
+ nativeRotateBy(sx / pixelRatio, sy / pixelRatio, ex, ey, duration);
}
public void setContentPadding(int[] padding) {
if (isDestroyedOn("setContentPadding")) {
return;
}
- nativeSetContentPadding(nativeMapViewPtr,
+ nativeSetContentPadding(
padding[1] / pixelRatio,
padding[0] / pixelRatio,
padding[3] / pixelRatio,
@@ -520,28 +470,35 @@ final class NativeMapView {
if (isDestroyedOn("setBearing")) {
return;
}
- nativeSetBearing(nativeMapViewPtr, degrees, duration);
+ nativeSetBearing(degrees, duration);
}
public void setBearing(double degrees, double cx, double cy) {
if (isDestroyedOn("setBearing")) {
return;
}
- nativeSetBearingXY(nativeMapViewPtr, degrees, cx / pixelRatio, cy / pixelRatio);
+ setBearing(degrees, cx, cy, 0);
+ }
+
+ public void setBearing(double degrees, double fx, double fy, long duration) {
+ if (isDestroyedOn("setBearing")) {
+ return;
+ }
+ nativeSetBearingXY(degrees, fx / pixelRatio, fy / pixelRatio, duration);
}
public double getBearing() {
if (isDestroyedOn("getBearing")) {
return 0;
}
- return nativeGetBearing(nativeMapViewPtr);
+ return nativeGetBearing();
}
public void resetNorth() {
if (isDestroyedOn("resetNorth")) {
return;
}
- nativeResetNorth(nativeMapViewPtr);
+ nativeResetNorth();
}
public long addMarker(Marker marker) {
@@ -549,14 +506,14 @@ final class NativeMapView {
return 0;
}
Marker[] markers = {marker};
- return nativeAddMarkers(nativeMapViewPtr, markers)[0];
+ return nativeAddMarkers(markers)[0];
}
public long[] addMarkers(List<Marker> markers) {
if (isDestroyedOn("addMarkers")) {
return new long[] {};
}
- return nativeAddMarkers(nativeMapViewPtr, markers.toArray(new Marker[markers.size()]));
+ return nativeAddMarkers(markers.toArray(new Marker[markers.size()]));
}
public long addPolyline(Polyline polyline) {
@@ -564,14 +521,14 @@ final class NativeMapView {
return 0;
}
Polyline[] polylines = {polyline};
- return nativeAddPolylines(nativeMapViewPtr, polylines)[0];
+ return nativeAddPolylines(polylines)[0];
}
public long[] addPolylines(List<Polyline> polylines) {
if (isDestroyedOn("addPolylines")) {
return new long[] {};
}
- return nativeAddPolylines(nativeMapViewPtr, polylines.toArray(new Polyline[polylines.size()]));
+ return nativeAddPolylines(polylines.toArray(new Polyline[polylines.size()]));
}
public long addPolygon(Polygon polygon) {
@@ -579,14 +536,14 @@ final class NativeMapView {
return 0;
}
Polygon[] polygons = {polygon};
- return nativeAddPolygons(nativeMapViewPtr, polygons)[0];
+ return nativeAddPolygons(polygons)[0];
}
public long[] addPolygons(List<Polygon> polygons) {
if (isDestroyedOn("addPolygons")) {
return new long[] {};
}
- return nativeAddPolygons(nativeMapViewPtr, polygons.toArray(new Polygon[polygons.size()]));
+ return nativeAddPolygons(polygons.toArray(new Polygon[polygons.size()]));
}
public void updateMarker(Marker marker) {
@@ -595,21 +552,21 @@ final class NativeMapView {
}
LatLng position = marker.getPosition();
Icon icon = marker.getIcon();
- nativeUpdateMarker(nativeMapViewPtr, marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId());
+ nativeUpdateMarker(marker.getId(), position.getLatitude(), position.getLongitude(), icon.getId());
}
public void updatePolygon(Polygon polygon) {
if (isDestroyedOn("updatePolygon")) {
return;
}
- nativeUpdatePolygon(nativeMapViewPtr, polygon.getId(), polygon);
+ nativeUpdatePolygon(polygon.getId(), polygon);
}
public void updatePolyline(Polyline polyline) {
if (isDestroyedOn("updatePolyline")) {
return;
}
- nativeUpdatePolyline(nativeMapViewPtr, polyline.getId(), polyline);
+ nativeUpdatePolyline(polyline.getId(), polyline);
}
public void removeAnnotation(long id) {
@@ -624,99 +581,106 @@ final class NativeMapView {
if (isDestroyedOn("removeAnnotations")) {
return;
}
- nativeRemoveAnnotations(nativeMapViewPtr, ids);
+ nativeRemoveAnnotations(ids);
}
public long[] queryPointAnnotations(RectF rect) {
if (isDestroyedOn("queryPointAnnotations")) {
return new long[] {};
}
- return nativeQueryPointAnnotations(nativeMapViewPtr, rect);
+ return nativeQueryPointAnnotations(rect);
}
public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) {
if (isDestroyedOn("addAnnotationIcon")) {
return;
}
- nativeAddAnnotationIcon(nativeMapViewPtr, symbol, width, height, scale, pixels);
+ nativeAddAnnotationIcon(symbol, width, height, scale, pixels);
}
public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
if (isDestroyedOn("setVisibleCoordinateBounds")) {
return;
}
- nativeSetVisibleCoordinateBounds(nativeMapViewPtr, coordinates, padding, direction, duration);
+ nativeSetVisibleCoordinateBounds(coordinates, padding, direction, duration);
}
public void onLowMemory() {
if (isDestroyedOn("onLowMemory")) {
return;
}
- nativeOnLowMemory(nativeMapViewPtr);
+ nativeOnLowMemory();
}
public void setDebug(boolean debug) {
if (isDestroyedOn("setDebug")) {
return;
}
- nativeSetDebug(nativeMapViewPtr, debug);
+ nativeSetDebug(debug);
}
public void cycleDebugOptions() {
if (isDestroyedOn("cycleDebugOptions")) {
return;
}
- nativeToggleDebug(nativeMapViewPtr);
+ nativeCycleDebugOptions();
}
public boolean getDebug() {
if (isDestroyedOn("getDebug")) {
return false;
}
- return nativeGetDebug(nativeMapViewPtr);
+ return nativeGetDebug();
+ }
+
+ public void setEnableFps(boolean enable) {
+ if (isDestroyedOn("setEnableFps")) {
+ return;
+ }
+ nativeSetEnableFps(enable);
}
public boolean isFullyLoaded() {
if (isDestroyedOn("isFullyLoaded")) {
return false;
}
- return nativeIsFullyLoaded(nativeMapViewPtr);
+ return nativeIsFullyLoaded();
}
public void setReachability(boolean status) {
if (isDestroyedOn("setReachability")) {
return;
}
- nativeSetReachability(nativeMapViewPtr, status);
+ nativeSetReachability(status);
}
public double getMetersPerPixelAtLatitude(double lat) {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(nativeMapViewPtr, lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
if (isDestroyedOn("projectedMetersForLatLng")) {
return null;
}
- return nativeProjectedMetersForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
+ return nativeProjectedMetersForLatLng(latLng.getLatitude(), latLng.getLongitude());
}
public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) {
if (isDestroyedOn("latLngForProjectedMeters")) {
return new LatLng();
}
- return nativeLatLngForProjectedMeters(nativeMapViewPtr, projectedMeters.getNorthing(),
- projectedMeters.getEasting());
+ return nativeLatLngForProjectedMeters(projectedMeters.getNorthing(),
+ projectedMeters.getEasting()).wrap();
}
public PointF pixelForLatLng(LatLng latLng) {
if (isDestroyedOn("pixelForLatLng")) {
return new PointF();
}
- PointF pointF = nativePixelForLatLng(nativeMapViewPtr, latLng.getLatitude(), latLng.getLongitude());
+ PointF pointF = nativePixelForLatLng(latLng.getLatitude(), latLng.getLongitude());
pointF.set(pointF.x * pixelRatio, pointF.y * pixelRatio);
return pointF;
}
@@ -725,21 +689,21 @@ final class NativeMapView {
if (isDestroyedOn("latLngForPixel")) {
return new LatLng();
}
- return nativeLatLngForPixel(nativeMapViewPtr, pixel.x / pixelRatio, pixel.y / pixelRatio);
+ return nativeLatLngForPixel(pixel.x / pixelRatio, pixel.y / pixelRatio).wrap();
}
public double getTopOffsetPixelsForAnnotationSymbol(String symbolName) {
if (isDestroyedOn("getTopOffsetPixelsForAnnotationSymbol")) {
return 0;
}
- return nativeGetTopOffsetPixelsForAnnotationSymbol(nativeMapViewPtr, symbolName);
+ return nativeGetTopOffsetPixelsForAnnotationSymbol(symbolName);
}
public void jumpTo(double angle, LatLng center, double pitch, double zoom) {
if (isDestroyedOn("jumpTo")) {
return;
}
- nativeJumpTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
+ nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
}
public void easeTo(double angle, LatLng center, long duration, double pitch, double zoom,
@@ -747,7 +711,7 @@ final class NativeMapView {
if (isDestroyedOn("easeTo")) {
return;
}
- nativeEaseTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
+ nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
easingInterpolator);
}
@@ -755,115 +719,163 @@ final class NativeMapView {
if (isDestroyedOn("flyTo")) {
return;
}
- nativeFlyTo(nativeMapViewPtr, angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
+ nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
}
public double[] getCameraValues() {
if (isDestroyedOn("getCameraValues")) {
return new double[] {};
}
- return nativeGetCameraValues(nativeMapViewPtr);
+ return nativeGetCameraValues();
}
// Runtime style Api
public long getTransitionDuration() {
- return nativeGetTransitionDuration(nativeMapViewPtr);
+ return nativeGetTransitionDuration();
}
public void setTransitionDuration(long duration) {
- nativeSetTransitionDuration(nativeMapViewPtr, duration);
+ nativeSetTransitionDuration(duration);
}
public long getTransitionDelay() {
- return nativeGetTransitionDelay(nativeMapViewPtr);
+ return nativeGetTransitionDelay();
}
public void setTransitionDelay(long delay) {
- nativeSetTransitionDelay(nativeMapViewPtr, delay);
+ nativeSetTransitionDelay(delay);
+ }
+
+ public List<Layer> getLayers() {
+ if (isDestroyedOn("getLayers")) {
+ return null;
+ }
+ return Arrays.asList(nativeGetLayers());
}
public Layer getLayer(String layerId) {
if (isDestroyedOn("getLayer")) {
return null;
}
- return nativeGetLayer(nativeMapViewPtr, layerId);
+ return nativeGetLayer(layerId);
}
- public void addLayer(@NonNull Layer layer, @Nullable String before) {
- if (isDestroyedOn("")) {
+ public void addLayer(@NonNull Layer layer) {
+ if (isDestroyedOn("addLayer")) {
return;
}
- nativeAddLayer(nativeMapViewPtr, layer.getNativePtr(), before);
+ nativeAddLayer(layer.getNativePtr(), null);
}
- public void removeLayer(@NonNull String layerId) throws NoSuchLayerException {
- if (isDestroyedOn("removeLayer")) {
+ public void addLayerBelow(@NonNull Layer layer, @NonNull String below) {
+ if (isDestroyedOn("addLayerBelow")) {
return;
}
- nativeRemoveLayerById(nativeMapViewPtr, layerId);
+ nativeAddLayer(layer.getNativePtr(), below);
}
- public void removeLayer(@NonNull Layer layer) throws NoSuchLayerException {
- if (isDestroyedOn("removeLayer")) {
+ public void addLayerAbove(@NonNull Layer layer, @NonNull String above) {
+ if (isDestroyedOn("addLayerAbove")) {
+ return;
+ }
+ nativeAddLayerAbove(layer.getNativePtr(), above);
+ }
+
+ public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) {
+ if (isDestroyedOn("addLayerAt")) {
return;
}
- nativeRemoveLayer(nativeMapViewPtr, layer.getNativePtr());
+ nativeAddLayerAt(layer.getNativePtr(), index);
+ }
+
+ @Nullable
+ public Layer removeLayer(@NonNull String layerId) {
+ if (isDestroyedOn("removeLayer")) {
+ return null;
+ }
+ return nativeRemoveLayerById(layerId);
+ }
+
+ @Nullable
+ public Layer removeLayer(@NonNull Layer layer) {
+ if (isDestroyedOn("removeLayer")) {
+ return null;
+ }
+ nativeRemoveLayer(layer.getNativePtr());
+ return layer;
+ }
+
+ @Nullable
+ public Layer removeLayerAt(@IntRange(from = 0) int index) {
+ if (isDestroyedOn("removeLayerAt")) {
+ return null;
+ }
+ return nativeRemoveLayerAt(index);
+ }
+
+ public List<Source> getSources() {
+ if (isDestroyedOn("getSources")) {
+ return null;
+ }
+ return Arrays.asList(nativeGetSources());
}
public Source getSource(@NonNull String sourceId) {
if (isDestroyedOn("getSource")) {
return null;
}
- return nativeGetSource(nativeMapViewPtr, sourceId);
+ return nativeGetSource(sourceId);
}
public void addSource(@NonNull Source source) {
if (isDestroyedOn("addSource")) {
return;
}
- nativeAddSource(nativeMapViewPtr, source.getNativePtr());
+ nativeAddSource(source.getNativePtr());
}
- public void removeSource(@NonNull String sourceId) throws NoSuchSourceException {
+ @Nullable
+ public Source removeSource(@NonNull String sourceId) {
if (isDestroyedOn("removeSource")) {
- return;
+ return null;
}
- nativeRemoveSourceById(nativeMapViewPtr, sourceId);
+ return nativeRemoveSourceById(sourceId);
}
- public void removeSource(@NonNull Source source) throws NoSuchSourceException {
+ public Source removeSource(@NonNull Source source) {
if (isDestroyedOn("removeSource")) {
- return;
+ return null;
}
- nativeRemoveSource(nativeMapViewPtr, source.getNativePtr());
+ nativeRemoveSource(source.getNativePtr());
+ return source;
}
public void addImage(@NonNull String name, @NonNull Bitmap image) {
if (isDestroyedOn("addImage")) {
return;
}
- //Check/correct config
+ // Check/correct config
if (image.getConfig() != Bitmap.Config.ARGB_8888) {
image = image.copy(Bitmap.Config.ARGB_8888, false);
}
- //Get pixels
+ // Get pixels
ByteBuffer buffer = ByteBuffer.allocate(image.getByteCount());
image.copyPixelsToBuffer(buffer);
- //Determine pixel ratio
+ // Determine pixel ratio
float density = image.getDensity() == Bitmap.DENSITY_NONE ? Bitmap.DENSITY_NONE : image.getDensity();
float pixelRatio = density / DisplayMetrics.DENSITY_DEFAULT;
- nativeAddImage(nativeMapViewPtr, name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array());
+ nativeAddImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array());
}
public void removeImage(String name) {
if (isDestroyedOn("removeImage")) {
return;
}
- nativeRemoveImage(nativeMapViewPtr, name);
+ nativeRemoveImage(name);
}
// Feature querying
@@ -873,7 +885,7 @@ final class NativeMapView {
if (isDestroyedOn("queryRenderedFeatures")) {
return new ArrayList<>();
}
- Feature[] features = nativeQueryRenderedFeaturesForPoint(nativeMapViewPtr, coordinates.x / pixelRatio,
+ Feature[] features = nativeQueryRenderedFeaturesForPoint(coordinates.x / pixelRatio,
coordinates.y / pixelRatio, layerIds);
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
@@ -884,7 +896,7 @@ final class NativeMapView {
return new ArrayList<>();
}
Feature[] features = nativeQueryRenderedFeaturesForBox(
- nativeMapViewPtr,
+
coordinates.left / pixelRatio,
coordinates.top / pixelRatio,
coordinates.right / pixelRatio,
@@ -897,14 +909,14 @@ final class NativeMapView {
if (isDestroyedOn("scheduleTakeSnapshot")) {
return;
}
- nativeScheduleTakeSnapshot(nativeMapViewPtr);
+ nativeTakeSnapshot();
}
public void setApiBaseUrl(String baseUrl) {
if (isDestroyedOn("setApiBaseUrl")) {
return;
}
- nativeSetAPIBaseURL(nativeMapViewPtr, baseUrl);
+ fileSource.setApiBaseUrl(baseUrl);
}
public float getPixelRatio() {
@@ -920,7 +932,9 @@ final class NativeMapView {
//
protected void onInvalidate() {
- mapView.onInvalidate();
+ if (mapView != null) {
+ mapView.onInvalidate();
+ }
}
protected void onMapChanged(int rawChange) {
@@ -935,18 +949,9 @@ final class NativeMapView {
mapView.onFpsChanged(fps);
}
- protected void onSnapshotReady(byte[] bytes) {
- if (snapshotRequest != null && bytes != null) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inBitmap = snapshotRequest.getBitmap(); // the old Bitmap to be reused
- options.inMutable = true;
- options.inSampleSize = 1;
- Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
-
- MapboxMap.SnapshotReadyCallback callback = snapshotRequest.getCallback();
- if (callback != null) {
- callback.onSnapshotReady(bitmap);
- }
+ protected void onSnapshotReady(Bitmap bitmap) {
+ if (snapshotReadyCallback != null && bitmap != null) {
+ snapshotReadyCallback.onSnapshotReady(bitmap);
}
}
@@ -954,208 +959,192 @@ final class NativeMapView {
// JNI methods
//
- private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio,
- int availableProcessors, long totalMemory);
-
- private native void nativeDestroy(long nativeMapViewPtr);
+ private native void nativeInitialize(NativeMapView nativeMapView, FileSource fileSource,
+ float pixelRatio, int availableProcessors, long totalMemory);
- private native void nativeInitializeDisplay(long nativeMapViewPtr);
+ private native void nativeDestroy();
- private native void nativeTerminateDisplay(long nativeMapViewPtr);
+ private native void nativeInitializeDisplay();
- private native void nativeInitializeContext(long nativeMapViewPtr);
+ private native void nativeTerminateDisplay();
- private native void nativeTerminateContext(long nativeMapViewPtr);
+ private native void nativeInitializeContext();
- private native void nativeCreateSurface(long nativeMapViewPtr,
- Surface surface);
+ private native void nativeTerminateContext();
- private native void nativeDestroySurface(long nativeMapViewPtr);
+ private native void nativeCreateSurface(Object surface);
- private native void nativeUpdate(long nativeMapViewPtr);
+ private native void nativeDestroySurface();
- private native void nativeRender(long nativeMapViewPtr);
+ private native void nativeUpdate();
- private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
+ private native void nativeRender();
- private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
+ private native void nativeResizeView(int width, int height);
- private native void nativeAddClass(long nativeMapViewPtr, String clazz);
+ private native void nativeResizeFramebuffer(int fbWidth, int fbHeight);
- private native void nativeRemoveClass(long nativeMapViewPtr, String clazz);
+ private native void nativeSetStyleUrl(String url);
- private native boolean nativeHasClass(long nativeMapViewPtr, String clazz);
+ private native String nativeGetStyleUrl();
- private native void nativeSetClasses(long nativeMapViewPtr,
- List<String> classes);
+ private native void nativeSetStyleJson(String newStyleJson);
- private native List<String> nativeGetClasses(long nativeMapViewPtr);
+ private native String nativeGetStyleJson();
- private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
+ private native void nativeCancelTransitions();
- private native String nativeGetStyleUrl(long nativeMapViewPtr);
+ private native void nativeSetGestureInProgress(boolean inProgress);
- private native void nativeSetStyleJson(long nativeMapViewPtr, String newStyleJson);
+ private native void nativeMoveBy(double dx, double dy, long duration);
- private native String nativeGetStyleJson(long nativeMapViewPtr);
+ private native void nativeSetLatLng(double latitude, double longitude, long duration);
- private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken);
+ private native LatLng nativeGetLatLng();
- private native String nativeGetAccessToken(long nativeMapViewPtr);
+ private native void nativeResetPosition();
- private native void nativeCancelTransitions(long nativeMapViewPtr);
+ private native double nativeGetPitch();
- private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress);
+ private native void nativeSetPitch(double pitch, long duration);
- private native void nativeMoveBy(long nativeMapViewPtr, double dx,
- double dy, long duration);
+ private native void nativeScaleBy(double ds, double cx, double cy, long duration);
- private native void nativeSetLatLng(long nativeMapViewPtr, double latitude, double longitude,
- long duration);
+ private native void nativeSetScale(double scale, double cx, double cy, long duration);
- private native LatLng nativeGetLatLng(long nativeMapViewPtr);
+ private native double nativeGetScale();
- private native void nativeResetPosition(long nativeMapViewPtr);
+ private native void nativeSetZoom(double zoom, long duration);
- private native double nativeGetPitch(long nativeMapViewPtr);
+ private native double nativeGetZoom();
- private native void nativeSetPitch(long nativeMapViewPtr, double pitch, long duration);
+ private native void nativeResetZoom();
- private native void nativeScaleBy(long nativeMapViewPtr, double ds,
- double cx, double cy, long duration);
+ private native void nativeSetMinZoom(double zoom);
- private native void nativeSetScale(long nativeMapViewPtr, double scale,
- double cx, double cy, long duration);
+ private native double nativeGetMinZoom();
- private native double nativeGetScale(long nativeMapViewPtr);
+ private native void nativeSetMaxZoom(double zoom);
- private native void nativeSetZoom(long nativeMapViewPtr, double zoom,
- long duration);
+ private native double nativeGetMaxZoom();
- private native double nativeGetZoom(long nativeMapViewPtr);
+ private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration);
- private native void nativeResetZoom(long nativeMapViewPtr);
+ private native void nativeSetContentPadding(double top, double left, double bottom, double right);
- private native void nativeSetMinZoom(long nativeMapViewPtr, double zoom);
+ private native void nativeSetBearing(double degrees, long duration);
- private native double nativeGetMinZoom(long nativeMapViewPtr);
+ private native void nativeSetBearingXY(double degrees, double fx, double fy, long duration);
- private native void nativeSetMaxZoom(long nativeMapViewPtr, double zoom);
+ private native double nativeGetBearing();
- private native double nativeGetMaxZoom(long nativeMapViewPtr);
+ private native void nativeResetNorth();
- private native void nativeRotateBy(long nativeMapViewPtr, double sx,
- double sy, double ex, double ey, long duration);
+ private native void nativeUpdateMarker(long markerId, double lat, double lon, String iconId);
- private native void nativeSetContentPadding(long nativeMapViewPtr, double top, double left, double bottom,
- double right);
+ private native long[] nativeAddMarkers(Marker[] markers);
- private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
- long duration);
+ private native long[] nativeAddPolylines(Polyline[] polylines);
- private native void nativeSetBearingXY(long nativeMapViewPtr, double degrees,
- double cx, double cy);
+ private native long[] nativeAddPolygons(Polygon[] polygons);
- private native double nativeGetBearing(long nativeMapViewPtr);
+ private native void nativeRemoveAnnotations(long[] id);
- private native void nativeResetNorth(long nativeMapViewPtr);
+ private native long[] nativeQueryPointAnnotations(RectF rect);
- private native void nativeUpdateMarker(long nativeMapViewPtr, long markerId, double lat, double lon, String iconId);
+ private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels);
- private native long[] nativeAddMarkers(long nativeMapViewPtr, Marker[] markers);
+ private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding,
+ double direction, long duration);
- private native long[] nativeAddPolylines(long nativeMapViewPtr, Polyline[] polylines);
+ private native void nativeOnLowMemory();
- private native long[] nativeAddPolygons(long nativeMapViewPtr, Polygon[] polygons);
+ private native void nativeSetDebug(boolean debug);
- private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
+ private native void nativeCycleDebugOptions();
- private native long[] nativeQueryPointAnnotations(long nativeMapViewPtr, RectF rect);
+ private native boolean nativeGetDebug();
- private native void nativeAddAnnotationIcon(long nativeMapViewPtr, String symbol,
- int width, int height, float scale, byte[] pixels);
+ private native void nativeSetEnableFps(boolean enable);
- private native void nativeSetVisibleCoordinateBounds(long nativeMapViewPtr, LatLng[] coordinates,
- RectF padding, double direction, long duration);
+ private native boolean nativeIsFullyLoaded();
- private native void nativeOnLowMemory(long nativeMapViewPtr);
+ private native void nativeSetReachability(boolean status);
- private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
+ private native double nativeGetMetersPerPixelAtLatitude(double lat, double zoom);
- private native void nativeToggleDebug(long nativeMapViewPtr);
+ private native ProjectedMeters nativeProjectedMetersForLatLng(double latitude, double longitude);
- private native boolean nativeGetDebug(long nativeMapViewPtr);
+ private native LatLng nativeLatLngForProjectedMeters(double northing, double easting);
- private native boolean nativeIsFullyLoaded(long nativeMapViewPtr);
+ private native PointF nativePixelForLatLng(double lat, double lon);
- private native void nativeSetReachability(long nativeMapViewPtr, boolean status);
+ private native LatLng nativeLatLngForPixel(float x, float y);
- private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom);
+ private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName);
- private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, double latitude,
- double longitude);
+ private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom);
- private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, double northing, double easting);
+ private native void nativeEaseTo(double angle, double latitude, double longitude,
+ long duration, double pitch, double zoom,
+ boolean easingInterpolator);
- private native PointF nativePixelForLatLng(long nativeMapViewPtr, double lat, double lon);
+ private native void nativeFlyTo(double angle, double latitude, double longitude,
+ long duration, double pitch, double zoom);
- private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, float x, float y);
+ private native double[] nativeGetCameraValues();
- private native double nativeGetTopOffsetPixelsForAnnotationSymbol(long nativeMapViewPtr, String symbolName);
+ private native long nativeGetTransitionDuration();
- private native void nativeJumpTo(long nativeMapViewPtr, double angle, double latitude, double longitude,
- double pitch, double zoom);
+ private native void nativeSetTransitionDuration(long duration);
- private native void nativeEaseTo(long nativeMapViewPtr, double angle, double latitude, double longitude,
- long duration, double pitch, double zoom, boolean easingInterpolator);
+ private native long nativeGetTransitionDelay();
- private native void nativeFlyTo(long nativeMapViewPtr, double angle, double latitude, double longitude,
- long duration, double pitch, double zoom);
+ private native void nativeSetTransitionDelay(long delay);
- private native double[] nativeGetCameraValues(long nativeMapViewPtr);
+ private native Layer[] nativeGetLayers();
- private native long nativeGetTransitionDuration(long nativeMapViewPtr);
+ private native Layer nativeGetLayer(String layerId);
- private native void nativeSetTransitionDuration(long nativeMapViewPtr, long duration);
+ private native void nativeAddLayer(long layerPtr, String before) throws CannotAddLayerException;
- private native long nativeGetTransitionDelay(long nativeMapViewPtr);
+ private native void nativeAddLayerAbove(long layerPtr, String above) throws CannotAddLayerException;
- private native void nativeSetTransitionDelay(long nativeMapViewPtr, long delay);
+ private native void nativeAddLayerAt(long layerPtr, int index) throws CannotAddLayerException;
- private native Layer nativeGetLayer(long nativeMapViewPtr, String layerId);
+ private native Layer nativeRemoveLayerById(String layerId);
- private native void nativeAddLayer(long nativeMapViewPtr, long layerPtr, String before);
+ private native void nativeRemoveLayer(long layerId);
- private native void nativeRemoveLayerById(long nativeMapViewPtr, String layerId) throws NoSuchLayerException;
+ private native Layer nativeRemoveLayerAt(int index);
- private native void nativeRemoveLayer(long nativeMapViewPtr, long layerId) throws NoSuchLayerException;
+ private native Source[] nativeGetSources();
- private native Source nativeGetSource(long nativeMapViewPtr, String sourceId);
+ private native Source nativeGetSource(String sourceId);
- private native void nativeAddSource(long nativeMapViewPtr, long nativeSourcePtr);
+ private native void nativeAddSource(long nativeSourcePtr) throws CannotAddSourceException;
- private native void nativeRemoveSourceById(long nativeMapViewPtr, String sourceId) throws NoSuchSourceException;
+ private native Source nativeRemoveSourceById(String sourceId);
- private native void nativeRemoveSource(long nativeMapViewPtr, long sourcePtr) throws NoSuchSourceException;
+ private native void nativeRemoveSource(long sourcePtr);
- private native void nativeAddImage(long nativeMapViewPtr, String name, int width, int height, float pixelRatio,
+ private native void nativeAddImage(String name, int width, int height, float pixelRatio,
byte[] array);
- private native void nativeRemoveImage(long nativeMapViewPtr, String name);
+ private native void nativeRemoveImage(String name);
- private native void nativeUpdatePolygon(long nativeMapViewPtr, long polygonId, Polygon polygon);
+ private native void nativeUpdatePolygon(long polygonId, Polygon polygon);
- private native void nativeUpdatePolyline(long nativeMapviewPtr, long polylineId, Polyline polyline);
+ private native void nativeUpdatePolyline(long polylineId, Polyline polyline);
- private native void nativeScheduleTakeSnapshot(long nativeMapViewPtr);
+ private native void nativeTakeSnapshot();
- private native Feature[] nativeQueryRenderedFeaturesForPoint(long nativeMapViewPtr, float x, float y, String[]
+ private native Feature[] nativeQueryRenderedFeaturesForPoint(float x, float y, String[]
layerIds);
- private native Feature[] nativeQueryRenderedFeaturesForBox(long nativeMapViewPtr, float left, float top, float right,
- float bottom, String[] layerIds);
-
- private native void nativeSetAPIBaseURL(long nativeMapViewPtr, String baseUrl);
+ private native Feature[] nativeQueryRenderedFeaturesForBox(float left, float top,
+ float right, float bottom,
+ String[] layerIds);
int getWidth() {
if (isDestroyedOn("")) {
@@ -1187,27 +1176,9 @@ final class NativeMapView {
// Snapshot
//
- void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback, @Nullable Bitmap bitmap) {
- snapshotRequest = new SnapshotRequest(bitmap, callback);
+ void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) {
+ snapshotReadyCallback = callback;
scheduleTakeSnapshot();
render();
}
-
- private static class SnapshotRequest {
- private Bitmap bitmap;
- private MapboxMap.SnapshotReadyCallback callback;
-
- SnapshotRequest(Bitmap bitmap, MapboxMap.SnapshotReadyCallback callback) {
- this.bitmap = bitmap;
- this.callback = callback;
- }
-
- public Bitmap getBitmap() {
- return bitmap;
- }
-
- public MapboxMap.SnapshotReadyCallback getCallback() {
- return callback;
- }
- }
}
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 b7f93cc913..82d5dec6a0 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
@@ -117,4 +117,14 @@ public class Projection {
float getWidth() {
return nativeMapView.getWidth();
}
+
+ /**
+ * Calculates a zoom level based on minimum scale and current scale from MapView
+ *
+ * @param minScale The minimum scale to calculate the zoom level.
+ * @return zoom level that fits the MapView.
+ */
+ public double calculateZoom(float minScale) {
+ return Math.log(nativeMapView.getScale() * minScale) / Math.log(2);
+ }
}
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 90d933736b..77fea1a14a 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
@@ -152,4 +152,4 @@ public class SupportMapFragment extends Fragment {
public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
this.onMapReadyCallback = onMapReadyCallback;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index ff8d92d116..38f307f149 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -1,22 +1,19 @@
package com.mapbox.mapboxsdk.maps;
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.graphics.PointF;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-import android.support.v4.content.ContextCompat;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
import timber.log.Timber;
@@ -28,20 +25,23 @@ public final class TrackingSettings {
private final MyLocationView myLocationView;
private final UiSettings uiSettings;
private final FocalPointChangeListener focalPointChangedListener;
- private LocationListener myLocationListener;
+ private final CameraZoomInvalidator zoomInvalidator;
+ private LocationEngineListener myLocationListener;
private boolean myLocationEnabled;
private boolean dismissLocationTrackingOnGesture = true;
private boolean dismissBearingTrackingOnGesture = true;
+ private boolean isResetTrackingWithCameraPositionChange = true;
private MapboxMap.OnMyLocationTrackingModeChangeListener onMyLocationTrackingModeChangeListener;
private MapboxMap.OnMyBearingTrackingModeChangeListener onMyBearingTrackingModeChangeListener;
TrackingSettings(@NonNull MyLocationView myLocationView, UiSettings uiSettings,
- FocalPointChangeListener focalPointChangedListener) {
+ FocalPointChangeListener focalPointChangedListener, CameraZoomInvalidator zoomInvalidator) {
this.myLocationView = myLocationView;
this.focalPointChangedListener = focalPointChangedListener;
this.uiSettings = uiSettings;
+ this.zoomInvalidator = zoomInvalidator;
}
void initialise(MapboxMapOptions options) {
@@ -54,6 +54,8 @@ public final class TrackingSettings {
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, isDismissLocationTrackingOnGesture());
outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture());
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled());
+ outState.putBoolean(MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA,
+ isDismissTrackingModesForCameraPositionChange());
}
void onRestoreInstanceState(Bundle savedInstanceState) {
@@ -62,16 +64,18 @@ public final class TrackingSettings {
} catch (SecurityException ignore) {
// User did not accept location permissions
}
- //noinspection ResourceType
+ // noinspection ResourceType
setMyLocationTrackingMode(savedInstanceState.getInt(
MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE));
- //noinspection ResourceType
+ // noinspection ResourceType
setMyBearingTrackingMode(savedInstanceState.getInt(
MapboxConstants.STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE));
setDismissLocationTrackingOnGesture(savedInstanceState.getBoolean(
MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true));
setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean(
MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true));
+ setDismissTrackingModeForCameraPositionChange(savedInstanceState.getBoolean(
+ MapboxConstants.STATE_MY_TRACKING_MODE_DISMISS_FOR_CAMERA, true));
}
/**
@@ -92,8 +96,8 @@ public final class TrackingSettings {
myLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
- focalPointChangedListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(),
- myLocationView.getCenterY()));
+ zoomInvalidator.zoomTo(2.0);
+ focalPointChangedListener.onFocalPointChanged(myLocationView.getCenter());
} else {
focalPointChangedListener.onFocalPointChanged(null);
}
@@ -270,8 +274,39 @@ public final class TrackingSettings {
}
}
+ /**
+ * Reset the tracking modes as necessary. Animated camera position changes can reset the underlying tracking modes.
+ *
+ * @param cameraPosition the changed camera position
+ */
void resetTrackingModesIfRequired(CameraPosition cameraPosition) {
- resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1);
+ if (isDismissTrackingModesForCameraPositionChange()) {
+ resetTrackingModesIfRequired(cameraPosition.target != null, cameraPosition.bearing != -1);
+ }
+ }
+
+ /**
+ * Returns if a animation allows to dismiss a tracking mode.
+ * <p>
+ * By default this is set to true.
+ * </p>
+ *
+ * @return True if camera animations will allow to dismiss a tracking mode
+ */
+ public boolean isDismissTrackingModesForCameraPositionChange() {
+ return isResetTrackingWithCameraPositionChange;
+ }
+
+ /**
+ * Sets a flag to allow animated camera position changes to dismiss a tracking mode.
+ * <p>
+ * <p>
+ * </p>
+ *
+ * @param willAllowToDismiss True will allow animated camera changes dismiss a trackig mode
+ */
+ public void setDismissTrackingModeForCameraPositionChange(boolean willAllowToDismiss) {
+ isResetTrackingWithCameraPositionChange = willAllowToDismiss;
}
Location getMyLocation() {
@@ -280,7 +315,12 @@ public final class TrackingSettings {
void setOnMyLocationChangeListener(@Nullable final MapboxMap.OnMyLocationChangeListener listener) {
if (listener != null) {
- myLocationListener = new LocationListener() {
+ myLocationListener = new LocationEngineListener() {
+ @Override
+ public void onConnected() {
+ // Nothing
+ }
+
@Override
public void onLocationChanged(Location location) {
if (listener != null) {
@@ -288,20 +328,13 @@ public final class TrackingSettings {
}
}
};
- LocationServices.getLocationServices(myLocationView.getContext()).addLocationListener(myLocationListener);
+ LocationSource.getLocationEngine(myLocationView.getContext()).addLocationEngineListener(myLocationListener);
} else {
- LocationServices.getLocationServices(myLocationView.getContext()).removeLocationListener(myLocationListener);
+ LocationSource.getLocationEngine(myLocationView.getContext()).removeLocationEngineListener(myLocationListener);
myLocationListener = null;
}
}
- boolean isPermissionsAccepted() {
- return (ContextCompat.checkSelfPermission(myLocationView.getContext(),
- Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED)
- || ContextCompat.checkSelfPermission(myLocationView.getContext(),
- Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
- }
-
void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener listener) {
this.onMyLocationTrackingModeChangeListener = listener;
}
@@ -320,7 +353,7 @@ public final class TrackingSettings {
}
void setMyLocationEnabled(boolean locationEnabled) {
- if (!isPermissionsAccepted()) {
+ if (!PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) {
Timber.e("Could not activate user location tracking: "
+ "user did not accept the permission or permissions were not requested.");
return;
@@ -343,4 +376,8 @@ public final class TrackingSettings {
void onStop() {
myLocationView.onStop();
}
+
+ interface CameraZoomInvalidator {
+ void zoomTo(double zoomLevel);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 88acc13356..0f6b146907 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -73,7 +73,7 @@ final class Transform implements MapView.OnMapChangedListener {
@Override
public void onMapChanged(@MapView.MapChange int change) {
if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
- invalidateCameraPosition();
+ updateCameraPosition(invalidateCameraPosition());
if (cameraCancelableCallback != null) {
cameraCancelableCallback.onFinish();
cameraCancelableCallback = null;
@@ -84,47 +84,50 @@ final class Transform implements MapView.OnMapChangedListener {
@UiThread
final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, MapboxMap.CancelableCallback callback) {
- cameraPosition = update.getCameraPosition(mapboxMap);
- trackingSettings.resetTrackingModesIfRequired(cameraPosition);
- cancelTransitions();
- mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
- if (callback != null) {
- callback.onFinish();
+ CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
+ if (!cameraPosition.equals(this.cameraPosition)) {
+ trackingSettings.resetTrackingModesIfRequired(cameraPosition);
+ cancelTransitions();
+ mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
+ if (callback != null) {
+ callback.onFinish();
+ }
}
}
@UiThread
final void easeCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator,
- boolean resetTrackingMode, final MapboxMap.CancelableCallback callback) {
- cameraPosition = update.getCameraPosition(mapboxMap);
- if (resetTrackingMode) {
+ final MapboxMap.CancelableCallback callback) {
+ CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
+ if (!cameraPosition.equals(this.cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(cameraPosition);
- }
+ cancelTransitions();
+ if (callback != null) {
+ cameraCancelableCallback = callback;
+ mapView.addOnMapChangedListener(this);
+ }
- cancelTransitions();
- if (callback != null) {
- cameraCancelableCallback = callback;
- mapView.addOnMapChangedListener(this);
+ mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
+ cameraPosition.zoom, easingInterpolator);
}
-
- mapView.easeTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
- cameraPosition.zoom, easingInterpolator);
}
@UiThread
final void animateCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs,
final MapboxMap.CancelableCallback callback) {
- cameraPosition = update.getCameraPosition(mapboxMap);
- trackingSettings.resetTrackingModesIfRequired(cameraPosition);
+ CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
+ if (!cameraPosition.equals(this.cameraPosition)) {
+ trackingSettings.resetTrackingModesIfRequired(cameraPosition);
- cancelTransitions();
- if (callback != null) {
- cameraCancelableCallback = callback;
- mapView.addOnMapChangedListener(this);
- }
+ cancelTransitions();
+ if (callback != null) {
+ cameraCancelableCallback = callback;
+ mapView.addOnMapChangedListener(this);
+ }
- mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
- cameraPosition.zoom);
+ mapView.flyTo(cameraPosition.bearing, cameraPosition.target, getDurationNano(durationMs), cameraPosition.tilt,
+ cameraPosition.zoom);
+ }
}
@UiThread
@@ -186,6 +189,10 @@ final class Transform implements MapView.OnMapChangedListener {
}
}
+ void setZoom(double zoom) {
+ mapView.setZoom(zoom);
+ }
+
// Direction
double getBearing() {
double direction = -mapView.getBearing();
@@ -218,6 +225,13 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.setBearing(bearing, focalX, focalY);
}
+ void setBearing(double bearing, float focalX, float focalY, long duration) {
+ if (myLocationView != null) {
+ myLocationView.setBearing(bearing);
+ }
+ mapView.setBearing(bearing, focalX, focalY, duration);
+ }
+
//
// LatLng / CenterCoordinate
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 bb5271313b..8a3ae1e4f3 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
@@ -48,6 +48,9 @@ public final class UiSettings {
private boolean zoomControlsEnabled;
+ private boolean doubleTapGesturesEnabled = true;
+ private boolean doubleTapGestureChangeAllowed = true;
+
private boolean deselectMarkersOnTap = true;
private PointF userProvidedFocalPoint;
@@ -99,6 +102,8 @@ public final class UiSettings {
setTiltGesturesEnabled(options.getTiltGesturesEnabled());
setTiltGestureChangeAllowed(options.getTiltGesturesEnabled());
setZoomControlsEnabled(options.getZoomControlsEnabled());
+ setDoubleTapGesturesEnabled(options.getDoubleTapGesturesEnabled());
+ setDoubleTapGestureChangeAllowed(options.getDoubleTapGesturesEnabled());
}
private void saveGestures(Bundle outState) {
@@ -110,6 +115,8 @@ public final class UiSettings {
outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE, isRotateGestureChangeAllowed());
outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED, isTiltGesturesEnabled());
outState.putBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE, isTiltGestureChangeAllowed());
+ outState.putBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED, isDoubleTapGesturesEnabled());
+ outState.putBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED_CHANGE, isDoubleTapGestureChangeAllowed());
}
private void restoreGestures(Bundle savedInstanceState) {
@@ -121,6 +128,8 @@ public final class UiSettings {
setRotateGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED_CHANGE));
setTiltGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED));
setTiltGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_TILT_ENABLED_CHANGE));
+ setDoubleTapGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED));
+ setDoubleTapGestureChangeAllowed(savedInstanceState.getBoolean(MapboxConstants.STATE_DOUBLE_TAP_ENABLED_CHANGE));
}
private void initialiseCompass(MapboxMapOptions options, Resources resources) {
@@ -696,6 +705,41 @@ public final class UiSettings {
}
/**
+ * <p>
+ * Changes whether the user may zoom the map with a double tap.
+ * </p>
+ * <p>
+ * This setting controls only user interactions with the map. If you set the value to false,
+ * you may still change the map location programmatically.
+ * </p>
+ * The default value is true.
+ *
+ * @param doubleTapGesturesEnabled If true, zooming with a double tap is enabled.
+ */
+ public void setDoubleTapGesturesEnabled(boolean doubleTapGesturesEnabled) {
+ if (doubleTapGestureChangeAllowed) {
+ this.doubleTapGesturesEnabled = doubleTapGesturesEnabled;
+ }
+ }
+
+ /**
+ * Returns whether the user may zoom the map with a double tap.
+ *
+ * @return If true, zooming with a double tap is enabled.
+ */
+ public boolean isDoubleTapGesturesEnabled() {
+ return doubleTapGesturesEnabled;
+ }
+
+ void setDoubleTapGestureChangeAllowed(boolean doubleTapGestureChangeAllowed) {
+ this.doubleTapGestureChangeAllowed = doubleTapGestureChangeAllowed;
+ }
+
+ boolean isDoubleTapGestureChangeAllowed() {
+ return doubleTapGestureChangeAllowed;
+ }
+
+ /**
* Gets whether the markers are automatically deselected (and therefore, their infowindows
* closed) when a map tap is detected.
*
@@ -771,6 +815,7 @@ public final class UiSettings {
setRotateGesturesEnabled(enabled);
setTiltGesturesEnabled(enabled);
setZoomGesturesEnabled(enabled);
+ setDoubleTapGesturesEnabled(enabled);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
index dc4a21f2fe..6d8adc1e2a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
@@ -1,17 +1,20 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.content.Context;
+import android.graphics.PointF;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
+import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.maps.FocalPointChangeListener;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import java.lang.ref.WeakReference;
@@ -25,15 +28,16 @@ import java.lang.ref.WeakReference;
* use {@link com.mapbox.mapboxsdk.maps.UiSettings}.
* </p>
*/
-public final class CompassView extends ImageView implements Runnable {
+public final class CompassView extends AppCompatImageView implements Runnable, FocalPointChangeListener {
private static final long TIME_WAIT_IDLE = 500;
private static final long TIME_FADE_ANIMATION = TIME_WAIT_IDLE;
private static final long TIME_MAP_NORTH_ANIMATION = 150;
- private double direction = 0.0;
+ private float rotation = 0.0f;
private boolean fadeCompassViewFacingNorth = true;
private ViewPropertyAnimatorCompat fadeAnimator;
+ private PointF focalPoint;
public CompassView(Context context) {
super(context);
@@ -78,8 +82,8 @@ public final class CompassView extends ImageView implements Runnable {
}
public boolean isFacingNorth() {
- // increase range more than just 0.0
- return direction >= 359.0 || direction <= 1.0;
+ // increase range of facing north to more than only 0.0
+ return Math.abs(rotation) >= 359.0 || Math.abs(rotation) <= 1.0;
}
@Override
@@ -96,8 +100,19 @@ public final class CompassView extends ImageView implements Runnable {
}
}
- public void update(final double direction) {
- this.direction = direction;
+ @Nullable
+ PointF getFocalPoint() {
+ return focalPoint;
+ }
+
+ /**
+ * Updates the direction of the compass.
+ *
+ * @param bearing the direction value of the map
+ */
+ public void update(final double bearing) {
+ // compass needs reverse bearing #8123
+ rotation = (float) -bearing;
if (!isEnabled()) {
return;
@@ -115,7 +130,7 @@ public final class CompassView extends ImageView implements Runnable {
setVisibility(View.VISIBLE);
}
- setRotation((float) direction);
+ setRotation(rotation);
}
public void fadeCompassViewFacingNorth(boolean compassFadeFacingNorth) {
@@ -143,6 +158,11 @@ public final class CompassView extends ImageView implements Runnable {
}
}
+ @Override
+ public void onFocalPointChanged(PointF pointF) {
+ focalPoint = pointF;
+ }
+
static class CompassClickListener implements View.OnClickListener {
private WeakReference<MapboxMap> mapboxMap;
@@ -158,7 +178,12 @@ public final class CompassView extends ImageView implements Runnable {
final MapboxMap mapboxMap = this.mapboxMap.get();
final CompassView compassView = this.compassView.get();
if (mapboxMap != null && compassView != null) {
- mapboxMap.resetNorth();
+ PointF focalPoint = compassView.getFocalPoint();
+ if (focalPoint != null) {
+ mapboxMap.setFocalBearing(0, focalPoint.x, focalPoint.y, TIME_MAP_NORTH_ANIMATION);
+ } else {
+ mapboxMap.setFocalBearing(0, mapboxMap.getWidth() / 2, mapboxMap.getHeight() / 2, TIME_MAP_NORTH_ANIMATION);
+ }
compassView.postDelayed(compassView, TIME_WAIT_IDLE + TIME_MAP_NORTH_ANIMATION);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index c7dd867f2d..2c3685b862 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -31,10 +31,12 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Projection;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
import java.lang.ref.WeakReference;
@@ -296,7 +298,7 @@ public class MyLocationView extends View {
}
// draw foreground
- if (myBearingTrackingMode == MyBearingTracking.NONE) {
+ if (myBearingTrackingMode == MyBearingTracking.NONE || !compassListener.isSensorAvailable()) {
if (foregroundDrawable != null) {
foregroundDrawable.draw(canvas);
}
@@ -308,8 +310,9 @@ public class MyLocationView extends View {
public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
this.tilt = tilt;
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
- mapboxMap.getUiSettings().setFocalPoint(new PointF(getCenterX(), getCenterY()));
+ mapboxMap.getUiSettings().setFocalPoint(getCenter());
}
+ invalidate();
}
public void setBearing(double bearing) {
@@ -319,7 +322,8 @@ public class MyLocationView extends View {
if (location != null) {
setCompass(location.getBearing() - bearing);
}
- } else if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ } else if (myBearingTrackingMode == MyBearingTracking.COMPASS
+ && compassListener.isSensorAvailable()) {
setCompass(magneticHeading - bearing);
}
}
@@ -327,13 +331,14 @@ public class MyLocationView extends View {
public void setCameraPosition(CameraPosition position) {
if (position != null) {
- setTilt(position.tilt);
setBearing(position.bearing);
+ setTilt(position.tilt);
}
}
public void onStart() {
- if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS
+ && compassListener.isSensorAvailable()) {
compassListener.onResume();
}
if (isEnabled()) {
@@ -366,8 +371,7 @@ public class MyLocationView extends View {
}
if (userLocationListener != null) {
- LocationServices services = LocationServices.getLocationServices(getContext());
- services.removeLocationListener(userLocationListener);
+ LocationSource.getLocationEngine(getContext()).removeLocationEngineListener(userLocationListener);
userLocationListener = null;
}
}
@@ -417,10 +421,10 @@ public class MyLocationView extends View {
* @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
*/
private void toggleGps(boolean enableGps) {
- LocationServices locationServices = LocationServices.getLocationServices(getContext());
+ LocationEngine locationEngine = LocationSource.getLocationEngine(getContext());
if (enableGps) {
// Set an initial location if one available
- Location lastLocation = locationServices.getLastLocation();
+ Location lastLocation = locationEngine.getLastLocation();
if (lastLocation != null) {
setLocation(lastLocation);
@@ -430,14 +434,14 @@ public class MyLocationView extends View {
userLocationListener = new GpsLocationListener(this);
}
- locationServices.addLocationListener(userLocationListener);
+ locationEngine.addLocationEngineListener(userLocationListener);
} else {
// Disable location and user dot
location = null;
- locationServices.removeLocationListener(userLocationListener);
+ locationEngine.removeLocationEngineListener(userLocationListener);
}
- locationServices.toggleGPS(enableGps);
+ locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY);
}
public Location getLocation() {
@@ -456,7 +460,8 @@ public class MyLocationView extends View {
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
this.myBearingTrackingMode = myBearingTrackingMode;
- if (myBearingTrackingMode == MyBearingTracking.COMPASS) {
+ if (myBearingTrackingMode == MyBearingTracking.COMPASS
+ && compassListener.isSensorAvailable()) {
compassListener.onResume();
} else {
compassListener.onPause();
@@ -477,8 +482,19 @@ public class MyLocationView extends View {
if (location != null) {
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
// center map directly
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false);
mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/,
- false /*do not disable tracking*/, null);
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+
+ }
+
+ @Override
+ public void onFinish() {
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true);
+ }
+ });
} else {
// do not use interpolated location from tracking mode
latLng = null;
@@ -528,11 +544,15 @@ public class MyLocationView extends View {
directionAnimator.start();
}
- public float getCenterX() {
+ public PointF getCenter() {
+ return new PointF(getCenterX(), getCenterY());
+ }
+
+ private float getCenterX() {
return (getX() + getMeasuredWidth()) / 2 + contentPaddingX - projectedX;
}
- public float getCenterY() {
+ private float getCenterY() {
return (getY() + getMeasuredHeight()) / 2 + contentPaddingY - projectedY;
}
@@ -541,7 +561,7 @@ public class MyLocationView extends View {
contentPaddingY = (padding[1] - padding[3]) / 2;
}
- private static class GpsLocationListener implements LocationListener {
+ private static class GpsLocationListener implements LocationEngineListener {
private WeakReference<MyLocationView> userLocationView;
@@ -549,6 +569,15 @@ public class MyLocationView extends View {
userLocationView = new WeakReference<>(myLocationView);
}
+ @Override
+ public void onConnected() {
+ MyLocationView locationView = userLocationView.get();
+ if (locationView != null) {
+ Location location = LocationSource.getLocationEngine(locationView.getContext()).getLastLocation();
+ locationView.setLocation(location);
+ }
+ }
+
/**
* Callback method for receiving location updates from LocationServices.
*
@@ -587,6 +616,10 @@ public class MyLocationView extends View {
sensorManager.unregisterListener(this, rotationVectorSensor);
}
+ public boolean isSensorAvailable() {
+ return rotationVectorSensor != null;
+ }
+
@Override
public void onSensorChanged(SensorEvent event) {
@@ -619,8 +652,19 @@ public class MyLocationView extends View {
private void rotateCamera(float rotation) {
CameraPosition.Builder builder = new CameraPosition.Builder();
builder.bearing(rotation);
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false);
mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), COMPASS_UPDATE_RATE_MS,
- false /*linear interpolator*/, false /*do not disable tracking*/, null);
+ false /*linear interpolator*/, new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+
+ }
+
+ @Override
+ public void onFinish() {
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true);
+ }
+ });
}
@Override
@@ -734,9 +778,20 @@ public class MyLocationView extends View {
// accuracy
updateAccuracy(location);
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(false);
// ease to new camera position with a linear interpolator
mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), (int) animationDuration,
- false /*linear interpolator*/, false /*do not disable tracking*/, null);
+ false /*linear interpolator*/, new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+
+ }
+
+ @Override
+ public void onFinish() {
+ mapboxMap.getTrackingSettings().setDismissTrackingModeForCameraPositionChange(true);
+ }
+ });
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
index 6cfbfed733..e9d823ebda 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.maps.widgets;
-import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
@@ -289,8 +288,7 @@ public class MyLocationViewSettings {
private void invalidateFocalPointForTracking(MyLocationView myLocationView) {
if (!(myLocationView.getMyLocationTrackingMode() == MyLocationTracking.TRACKING_NONE)) {
- focalPointChangeListener.onFocalPointChanged(new PointF(myLocationView.getCenterX(),
- myLocationView.getCenterY()));
+ focalPointChangeListener.onFocalPointChanged(myLocationView.getCenter());
} else {
focalPointChangeListener.onFocalPointChanged(null);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
index 7c37569ae2..7be56fa694 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
@@ -7,6 +7,7 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
import com.mapbox.mapboxsdk.Mapbox;
@@ -27,11 +28,9 @@ public class ConnectivityReceiver extends BroadcastReceiver {
*/
public static synchronized ConnectivityReceiver instance(Context context) {
if (INSTANCE == null) {
- //Register new instance
- INSTANCE = new ConnectivityReceiver();
- context.registerReceiver(INSTANCE, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
-
- //Add default listeners
+ // Register new instance
+ INSTANCE = new ConnectivityReceiver(context.getApplicationContext());
+ // Add default listeners
INSTANCE.addListener(new NativeConnectivityListener());
}
@@ -39,8 +38,39 @@ public class ConnectivityReceiver extends BroadcastReceiver {
}
private List<ConnectivityListener> listeners = new CopyOnWriteArrayList<>();
+ private Context context;
+ private int activationCounter;
+
+ private ConnectivityReceiver(@NonNull Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Activates the connectivity receiver.
+ * <p>
+ * if the underlying connectivity receiver isn't active, register the connectivity receiver.
+ * </p>
+ */
+ @UiThread
+ public void activate() {
+ if (activationCounter == 0) {
+ context.registerReceiver(INSTANCE, new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE"));
+ }
+ activationCounter++;
+ }
- private ConnectivityReceiver() {
+ /**
+ * Deactivates the connectivity receiver.
+ * <p>
+ * if no other components are listening, unregister the underlying connectivity receiver.
+ * </p>
+ */
+ @UiThread
+ public void deactivate() {
+ activationCounter--;
+ if (activationCounter == 0) {
+ context.unregisterReceiver(INSTANCE);
+ }
}
/**
@@ -51,7 +81,7 @@ public class ConnectivityReceiver extends BroadcastReceiver {
boolean connected = isConnected(context);
Timber.v("Connected: " + connected);
- //Loop over listeners
+ // Loop over listeners
for (ConnectivityListener listener : listeners) {
listener.onNetworkStateChanged(connected);
}
@@ -92,5 +122,4 @@ public class ConnectivityReceiver extends BroadcastReceiver {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
-
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
index beaea73024..8bf19c4065 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -1,15 +1,12 @@
package com.mapbox.mapboxsdk.offline;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
-import com.mapbox.mapboxsdk.Mapbox;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import com.mapbox.mapboxsdk.storage.FileSource;
import java.io.File;
@@ -29,18 +26,13 @@ public class OfflineManager {
System.loadLibrary("mapbox-gl");
}
- // Default database name
- private static final String DATABASE_NAME = "mbgl-offline.db";
- /*
- * The maximumCacheSize parameter is a limit applied to non-offline resources only,
- * i.e. resources added to the database for the "ambient use" caching functionality.
- * There is no size limit for offline resources.
- */
- private static final long DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024;
+ // Native peer pointer
+ private long nativePtr;
- // Holds the pointer to JNI DefaultFileSource
- private long mDefaultFileSourcePtr = 0;
+ // Reference to the file source to keep it alive for the
+ // lifetime of this object
+ private final FileSource fileSource;
// Makes sure callbacks come back to the main thread
private Handler handler;
@@ -48,6 +40,9 @@ public class OfflineManager {
// This object is implemented as a singleton
private static OfflineManager instance;
+ // The application context
+ private Context context;
+
/**
* This callback receives an asynchronous response containing a list of all
* {@link OfflineRegion} in the database, or an error message otherwise.
@@ -89,77 +84,17 @@ public class OfflineManager {
}
/*
- * Constructors
+ * Constructor
*/
private OfflineManager(Context context) {
- // Get a pointer to the DefaultFileSource instance
- String assetRoot = getDatabasePath(context);
- String cachePath = assetRoot + File.separator + DATABASE_NAME;
- mDefaultFileSourcePtr = createDefaultFileSource(cachePath, assetRoot, DEFAULT_MAX_CACHE_SIZE);
- setAccessToken(mDefaultFileSourcePtr, Mapbox.getAccessToken());
+ this.context = context.getApplicationContext();
+ this.fileSource = FileSource.getInstance(context);
+ initialize(fileSource);
// Delete any existing previous ambient cache database
deleteAmbientDatabase(context);
}
- public static String getDatabasePath(Context context) {
- // Default value
- boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
-
- try {
- // Try getting a custom value from the app Manifest
- ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
- context.getPackageName(), PackageManager.GET_META_DATA);
- setStorageExternal = appInfo.metaData.getBoolean(
- MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
- MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
- } catch (PackageManager.NameNotFoundException exception) {
- Timber.e("Failed to read the package metadata: ", exception);
- } catch (Exception exception) {
- Timber.e("Failed to read the storage key: ", exception);
- }
-
- String databasePath = null;
- if (setStorageExternal && isExternalStorageReadable()) {
- try {
- // Try getting the external storage path
- databasePath = context.getExternalFilesDir(null).getAbsolutePath();
- } catch (NullPointerException exception) {
- Timber.e("Failed to obtain the external storage path: ", exception);
- }
- }
-
- if (databasePath == null) {
- // Default to internal storage
- databasePath = context.getFilesDir().getAbsolutePath();
- }
-
- return databasePath;
- }
-
- /**
- * Checks if external storage is available to at least read. In order for this to work, make
- * sure you include &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
- * (or WRITE_EXTERNAL_STORAGE) for API level &lt; 18 in your app Manifest.
- * <p>
- * Code from https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
- * </p>
- *
- * @return true if external storage is readable
- */
- public static boolean isExternalStorageReadable() {
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- return true;
- }
-
- Timber.w("External storage was requested but it isn't readable. For API level < 18"
- + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
- + " permissions in your app Manifest (defaulting to internal storage).");
-
- return false;
- }
-
private void deleteAmbientDatabase(final Context context) {
// Delete the file in a separate thread to avoid affecting the UI
new Thread(new Runnable() {
@@ -205,7 +140,8 @@ public class OfflineManager {
* @param callback the callback to be invoked
*/
public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) {
- listOfflineRegions(mDefaultFileSourcePtr, new ListOfflineRegionsCallback() {
+ listOfflineRegions(fileSource, new ListOfflineRegionsCallback() {
+
@Override
public void onList(final OfflineRegion[] offlineRegions) {
getHandler().post(new Runnable() {
@@ -249,12 +185,15 @@ public class OfflineManager {
@NonNull byte[] metadata,
@NonNull final CreateOfflineRegionCallback callback) {
- createOfflineRegion(mDefaultFileSourcePtr, definition, metadata, new CreateOfflineRegionCallback() {
+ ConnectivityReceiver.instance(context).activate();
+ createOfflineRegion(fileSource, definition, metadata, new CreateOfflineRegionCallback() {
+
@Override
public void onCreate(final OfflineRegion offlineRegion) {
getHandler().post(new Runnable() {
@Override
public void run() {
+ ConnectivityReceiver.instance(context).deactivate();
callback.onCreate(offlineRegion);
}
});
@@ -265,6 +204,7 @@ public class OfflineManager {
getHandler().post(new Runnable() {
@Override
public void run() {
+ ConnectivityReceiver.instance(context).deactivate();
callback.onError(error);
}
});
@@ -276,29 +216,16 @@ public class OfflineManager {
* Changing or bypassing this limit without permission from Mapbox is prohibited
* by the Mapbox Terms of Service.
*/
- public void setOfflineMapboxTileCountLimit(long limit) {
- setOfflineMapboxTileCountLimit(mDefaultFileSourcePtr, limit);
- }
-
-
- /*
- * Native methods
- */
- private native long createDefaultFileSource(
- String cachePath, String assetRoot, long maximumCacheSize);
-
- private native void setAccessToken(long defaultFileSourcePtr, String accessToken);
+ public native void setOfflineMapboxTileCountLimit(long limit);
- private native String getAccessToken(long defaultFileSourcePtr);
+ private native void initialize(FileSource fileSource);
- private native void listOfflineRegions(
- long defaultFileSourcePtr, ListOfflineRegionsCallback callback);
+ @Override
+ protected native void finalize() throws Throwable;
- private native void createOfflineRegion(
- long defaultFileSourcePtr, OfflineRegionDefinition definition,
- byte[] metadata, CreateOfflineRegionCallback callback);
+ private native void listOfflineRegions(FileSource fileSource, ListOfflineRegionsCallback callback);
- private native void setOfflineMapboxTileCountLimit(
- long defaultFileSourcePtr, long limit);
+ private native void createOfflineRegion(FileSource fileSource, OfflineRegionDefinition definition,
+ byte[] metadata, CreateOfflineRegionCallback callback);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index a4d8a646d3..a55e8dd848 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -5,7 +5,7 @@ import android.os.Looper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-import timber.log.Timber;
+import com.mapbox.mapboxsdk.storage.FileSource;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -25,22 +25,25 @@ public class OfflineRegion {
System.loadLibrary("mapbox-gl");
}
- // Parent OfflineManager
- private OfflineManager offlineManager;
-
// Members
- private long mId = 0;
- private OfflineRegionDefinition mDefinition = null;
+
+ // Holds the pointer to JNI OfflineRegion
+ private long nativePtr;
+
+ // Holds a reference to the FileSource to keep it alive
+ private FileSource fileSource;
+
+ //Region id
+ private long id;
+
+ private OfflineRegionDefinition definition;
/**
* Arbitrary binary region metadata. The contents are opaque to the SDK implementation;
* it just stores and retrieves a byte[]. Check the `OfflineActivity` in the TestApp
* for a sample implementation that uses JSON to store an offline region name.
*/
- private byte[] mMetadata = null;
-
- // Holds the pointer to JNI OfflineRegion
- private long mOfflineRegionPtr = 0;
+ private byte[] metadata;
// Makes sure callbacks come back to the main thread
private Handler handler;
@@ -197,19 +200,22 @@ public class OfflineRegion {
if (state == STATE_ACTIVE) {
return true;
}
- if (isDeliveringInactiveMessages()) {
- return true;
- }
- return false;
+ return isDeliveringInactiveMessages();
}
- /*
+ /**
* Constructor
+ *
+ * For JNI use only, to create a new offline region, use
+ * {@link OfflineManager#createOfflineRegion} instead.
*/
-
- private OfflineRegion() {
- // For JNI use only, to create a new offline region, use
- // OfflineManager.createOfflineRegion() instead.
+ private OfflineRegion(long offlineRegionPtr, FileSource fileSource, long id,
+ OfflineRegionDefinition definition, byte[] metadata) {
+ this.fileSource = fileSource;
+ this.id = id;
+ this.definition = definition;
+ this.metadata = metadata;
+ initialize(offlineRegionPtr, fileSource);
}
/*
@@ -217,15 +223,15 @@ public class OfflineRegion {
*/
public long getID() {
- return mId;
+ return id;
}
public OfflineRegionDefinition getDefinition() {
- return mDefinition;
+ return definition;
}
public byte[] getMetadata() {
- return mMetadata;
+ return metadata;
}
private Handler getHandler() {
@@ -383,7 +389,7 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
- mMetadata = metadata;
+ OfflineRegion.this.metadata = metadata;
callback.onUpdate(metadata);
}
});
@@ -401,33 +407,18 @@ public class OfflineRegion {
});
}
- @Override
- protected void finalize() {
- try {
- super.finalize();
- destroyOfflineRegion();
- } catch (Throwable throwable) {
- Timber.e("Failed to finalize OfflineRegion: " + throwable.getMessage());
- }
- }
-
- /*
- * Native methods
- */
+ private native void initialize(long offlineRegionPtr, FileSource fileSource);
- private native void destroyOfflineRegion();
+ @Override
+ protected native void finalize();
- private native void setOfflineRegionObserver(
- OfflineRegionObserver observerCallback);
+ private native void setOfflineRegionObserver(OfflineRegionObserver callback);
- private native void setOfflineRegionDownloadState(
- @DownloadState int offlineRegionDownloadState);
+ private native void setOfflineRegionDownloadState(@DownloadState int offlineRegionDownloadState);
- private native void getOfflineRegionStatus(
- OfflineRegionStatusCallback statusCallback);
+ private native void getOfflineRegionStatus(OfflineRegionStatusCallback callback);
- private native void deleteOfflineRegion(
- OfflineRegionDeleteCallback deleteCallback);
+ private native void deleteOfflineRegion(OfflineRegionDeleteCallback callback);
private native void updateOfflineRegionMetadata(byte[] metadata, OfflineRegionUpdateMetadataCallback callback);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
index 60c4a8661c..83f3c06d68 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionError.java
@@ -25,25 +25,23 @@ public class OfflineRegionError {
public static final String REASON_OTHER = "REASON_OTHER";
@ErrorReason
- private String reason;
+ private final String reason;
/**
* /* An error message from the request handler, e.g. a server message or a system message
* /* informing the user about the reason for the failure.
*/
- private String message;
+ private final String message;
- /*
- * Constructors
- */
+ // Constructors
- private OfflineRegionError() {
+ private OfflineRegionError(String reason, String message) {
// For JNI use only
+ this.reason = reason;
+ this.message = message;
}
- /*
- * Getters
- */
+ // Getters
@ErrorReason
public String getReason() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
index 11f2da132d..9c3655fbec 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
@@ -56,24 +56,29 @@ public class OfflineRegionStatus {
/*
* Use setObserver(OfflineRegionObserver observer) to obtain a OfflineRegionStatus object.
+ *
+ * For JNI use only
*/
-
- private OfflineRegionStatus() {
- // For JNI use only
+ private OfflineRegionStatus(int downloadState, long completedResourceCount,
+ long completedResourceSize, long completedTileCount,
+ long completedTileSize, long requiredResourceCount,
+ boolean requiredResourceCountIsPrecise) {
+ this.downloadState = downloadState;
+ this.completedResourceCount = completedResourceCount;
+ this.completedResourceSize = completedResourceSize;
+ this.completedTileCount = completedTileCount;
+ this.completedTileSize = completedTileSize;
+ this.requiredResourceCount = requiredResourceCount;
+ this.requiredResourceCountIsPrecise = requiredResourceCountIsPrecise;
}
- /*
+ /**
* Is the region complete?
*/
-
public boolean isComplete() {
return (completedResourceCount == requiredResourceCount);
}
- /*
- * Getters
- */
-
@OfflineRegion.DownloadState
public int getDownloadState() {
return downloadState;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
index 5fc844afe5..f8ec0f3d39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
@@ -21,16 +21,18 @@ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefiniti
private double maxZoom;
private float pixelRatio;
- /*
- * Constructors
+ /**
+ * Constructor
+ *
+ * @param styleURL the style
+ * @param bounds the bounds
+ * @param minZoom min zoom
+ * @param maxZoom max zoom
+ * @param pixelRatio pixel ratio of the device
*/
-
- private OfflineTilePyramidRegionDefinition() {
- // For JNI use only
- }
-
public OfflineTilePyramidRegionDefinition(
String styleURL, LatLngBounds bounds, double minZoom, double maxZoom, float pixelRatio) {
+ // Note: Also used in JNI
this.styleURL = styleURL;
this.bounds = bounds;
this.minZoom = minZoom;
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
new file mode 100644
index 0000000000..8681777023
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -0,0 +1,135 @@
+package com.mapbox.mapboxsdk.storage;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+
+import timber.log.Timber;
+
+/**
+ * Holds a central reference to the core's DefaultFileSource for as long as
+ * there are active mapviews / offline managers
+ */
+public class FileSource {
+
+ /**
+ * This callback allows implementors to transform URLs before they are requested
+ * from the internet. This can be used add or remove custom parameters, or reroute
+ * certain requests to other servers or endpoints.
+ */
+ public interface ResourceTransformCallback {
+
+ /**
+ * Called whenever a URL needs to be transformed.
+ *
+ * @param kind The kind of URL to be transformed.
+ * @return A URL that will now be downloaded.
+ */
+ String onURL(@Resource.Kind int kind, String url);
+
+ }
+
+ // File source instance is kept alive after initialization
+ private static FileSource INSTANCE;
+
+ public static synchronized FileSource getInstance(Context context) {
+ if (INSTANCE == null) {
+ String cachePath = getCachePath(context);
+ String apkPath = context.getPackageCodePath();
+ INSTANCE = new FileSource(cachePath, apkPath);
+ }
+
+ return INSTANCE;
+ }
+
+ public static String getCachePath(Context context) {
+ // Default value
+ boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
+
+ try {
+ // Try getting a custom value from the app Manifest
+ ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(),
+ PackageManager.GET_META_DATA);
+ setStorageExternal = appInfo.metaData.getBoolean(
+ MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
+ MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
+ } catch (PackageManager.NameNotFoundException exception) {
+ Timber.e("Failed to read the package metadata: ", exception);
+ } catch (Exception exception) {
+ Timber.e("Failed to read the storage key: ", exception);
+ }
+
+ String cachePath = null;
+ if (setStorageExternal && isExternalStorageReadable()) {
+ try {
+ // Try getting the external storage path
+ cachePath = context.getExternalFilesDir(null).getAbsolutePath();
+ } catch (NullPointerException exception) {
+ Timber.e("Failed to obtain the external storage path: ", exception);
+ }
+ }
+
+ if (cachePath == null) {
+ // Default to internal storage
+ cachePath = context.getFilesDir().getAbsolutePath();
+ }
+
+ return cachePath;
+ }
+
+ /**
+ * Checks if external storage is available to at least read. In order for this to work, make
+ * sure you include &lt;uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&gt;
+ * (or WRITE_EXTERNAL_STORAGE) for API level &lt; 18 in your app Manifest.
+ * <p>
+ * Code from https://developer.android.com/guide/topics/data/data-storage.html#filesExternal
+ * </p>
+ *
+ * @return true if external storage is readable
+ */
+ public static boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+
+ Timber.w("External storage was requested but it isn't readable. For API level < 18"
+ + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE"
+ + " permissions in your app Manifest (defaulting to internal storage).");
+
+ return false;
+ }
+
+ private long nativePtr;
+
+ private FileSource(String cachePath, String apkPath) {
+ initialize(Mapbox.getAccessToken(), cachePath, apkPath);
+ }
+
+ public native void setAccessToken(@NonNull String accessToken);
+
+ public native String getAccessToken();
+
+ public native void setApiBaseUrl(String baseUrl);
+
+ /**
+ * Sets a callback for transforming URLs requested from the internet
+ * <p>
+ * The callback will be executed on the main thread once for every requested URL.
+ * </p>
+ *
+ * @param callback the callback to be invoked
+ */
+ public native void setResourceTransform(@NonNull final ResourceTransformCallback callback);
+
+ private native void initialize(String accessToken, String cachePath, String apkPath);
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
new file mode 100644
index 0000000000..af98a46a9b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/Resource.java
@@ -0,0 +1,54 @@
+package com.mapbox.mapboxsdk.storage;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public final class Resource {
+ // Note: Keep this in sync with include/mbgl/storage/resource.hpp
+
+ @IntDef( {UNKNOWN, STYLE, SOURCE, TILE, GLYPHS, SPRITE_IMAGE, SPRITE_JSON})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Kind {
+ }
+
+ /**
+ * Unknown type
+ */
+ public static final int UNKNOWN = 0;
+
+ /**
+ * Style sheet JSON file
+ */
+ public static final int STYLE = 1;
+
+ /**
+ * TileJSON file as specified in https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sources
+ */
+ public static final int SOURCE = 2;
+
+ /**
+ * A vector or raster tile as described in the style sheet at
+ * https://www.mapbox.com/mapbox-gl-js/style-spec/#sources
+ */
+ public static final int TILE = 3;
+
+ /**
+ * Signed distance field glyphs for text rendering. These are the URLs specified in the style
+ * in https://www.mapbox.com/mapbox-gl-js/style-spec/#root-glyphs
+ */
+ public static final int GLYPHS = 4;
+
+ /**
+ * Image part of a sprite sheet. It is constructed of the prefix in
+ * https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a PNG file extension.
+ */
+ public static final int SPRITE_IMAGE = 5;
+
+ /**
+ * JSON part of a sprite sheet. It is constructed of the prefix in
+ * https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a JSON file extension.
+ */
+ public static final int SPRITE_JSON = 6;
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java
new file mode 100644
index 0000000000..bb87fe8a39
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CameraFunction.java
@@ -0,0 +1,50 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+/**
+ * Camera function. Functions that take camera properties as input (zoom for now)
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom level.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements: the first is a zoom level and the second is
+ * a function output value.
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see Function#zoom
+ */
+public class CameraFunction<I extends Number, O> extends Function<I, O> {
+
+ /**
+ * Create an exponential camera function
+ *
+ * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#exponential(float, Stop[])}
+ */
+ CameraFunction(@NonNull ExponentialStops<I, O> stops) {
+ super(stops);
+ }
+
+ /**
+ * Create an interval camera function
+ *
+ * @param stops @see {@link com.mapbox.mapboxsdk.style.functions.stops.Stops#interval(Stop[])}
+ */
+ CameraFunction(@NonNull IntervalStops<I, O> stops) {
+ super(stops);
+ }
+
+ /**
+ * JNI constructor
+ */
+ @Keep
+ private CameraFunction(Stops<I, O> stops) {
+ super(stops);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
new file mode 100644
index 0000000000..1db14afc5f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/CompositeFunction.java
@@ -0,0 +1,99 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+/**
+ * Composite functions combine {@link android.graphics.Camera} and {@link SourceFunction}s.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param <Z> the zoom type (usually Float)
+ * @param <I> the input type (the feature property type)
+ * @param <O> the output type (the property type)
+ * @see Function#composite
+ */
+public class CompositeFunction<Z extends Number, I, O> extends Function<Stop.CompositeValue<Z, I>, O> {
+
+ private final String property;
+ private O defaultValue;
+
+ CompositeFunction(@NonNull String property,
+ @NonNull CategoricalStops<Stop.CompositeValue<Z, I>, O> stops) {
+ this(null, property, stops);
+ }
+
+ CompositeFunction(@NonNull String property,
+ @NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) {
+ this(null, property, stops);
+ }
+
+ CompositeFunction(@NonNull String property,
+ @NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) {
+ this(null, property, stops);
+ }
+
+
+ /**
+ * JNI Constructor
+ */
+ private CompositeFunction(@Nullable O defaultValue, @NonNull String property,
+ @NonNull Stops<Stop.CompositeValue<Z, I>, O> stops) {
+ super(stops);
+ this.defaultValue = defaultValue;
+ this.property = property;
+ }
+
+ /**
+ * Set the default value
+ *
+ * @param defaultValue the default value to use when no other applies
+ * @return this (for chaining)
+ */
+ public CompositeFunction<Z, I, O> withDefaultValue(O defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
+ /**
+ * @return the defaultValue
+ */
+ @Nullable
+ public O getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the feature property name
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> valueObject = super.toValueObject();
+ valueObject.put(PROPERTY_KEY, property);
+ if (defaultValue != null) {
+ valueObject.put(DEFAULT_VALUE_KEY, defaultValue);
+ }
+ return valueObject;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
new file mode 100644
index 0000000000..e1e40821b1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
@@ -0,0 +1,300 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+import timber.log.Timber;
+
+/**
+ * Functions are used to change properties in relation to the state of the map.
+ * <p>
+ * The value for any layout or paint property may be specified as a function. Functions allow you to
+ * make the appearance of a map feature change with the current zoom level and/or the feature's properties.
+ *
+ * @param <I> the function's input type
+ * @param <O> the target property's value type. Make sure it matches.
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public class Function<I, O> {
+
+ static final String PROPERTY_KEY = "property";
+ static final String DEFAULT_VALUE_KEY = "default";
+
+ /**
+ * Create an exponential {@link CameraFunction}
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
+ *
+ * @param <Z> the zoom level type (Float, Integer)
+ * @param <O> the property type
+ * @param stops the stops implementation that define the function. @see {@link Stops#exponential(Stop[])}
+ * @return the {@link CameraFunction}
+ * @see CameraFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull ExponentialStops<Z, O> stops) {
+ return new CameraFunction<>(stops);
+ }
+
+ /**
+ * Create an interval {@link CameraFunction}
+ * <p>
+ * Zoom functions allow the appearance of a map feature to change with map’s zoom.
+ * Zoom functions can be used to create the illusion of depth and control data density.
+ * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
+ *
+ * @param <Z> the zoom level type (Float, Integer)
+ * @param <O> the property type
+ * @param stops the stops implementation that define the function. @see {@link Stops#interval(Stop[])}
+ * @return the {@link CameraFunction}
+ * @see CameraFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, O> CameraFunction<Z, O> zoom(@NonNull IntervalStops<Z, O> stops) {
+ return new CameraFunction<>(stops);
+ }
+
+ /**
+ * Create an exponential {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull ExponentialStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an identity {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <T> the function input/output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see IdentityStops
+ * @see Stops#identity()
+ * @see Stop#stop
+ */
+ public static <T> SourceFunction<T, T> property(@NonNull String property, @NonNull IdentityStops<T> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an interval {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull IntervalStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create an categorical {@link SourceFunction}
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param property the feature property name
+ * @param stops the stops
+ * @param <I> the function input type
+ * @param <O> the function output type
+ * @return the {@link SourceFunction}
+ * @see SourceFunction
+ * @see CategoricalStops
+ * @see Stops#categorical(Stop[])
+ * @see Stop#stop
+ */
+ public static <I, O> SourceFunction<I, O> property(@NonNull String property, @NonNull CategoricalStops<I, O> stops) {
+ return new SourceFunction<>(property, stops);
+ }
+
+ /**
+ * Create a composite, categorical function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see CategoricalStops
+ * @see Stops#categorical(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull CategoricalStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, stops);
+ }
+
+ /**
+ * Create a composite, exponential function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see ExponentialStops
+ * @see Stops#exponential(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull ExponentialStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, stops);
+ }
+
+ /**
+ * Create a composite, interval function.
+ * <p>
+ * Composite functions allow the appearance of a map feature to change with both its
+ * properties and zoom. Each stop is an array with two elements, the first is an object
+ * with a property input value and a zoom, and the second is a function output value. Note
+ * that support for property functions is not yet complete.
+ *
+ * @param property the feature property name for the source part of the function
+ * @param stops the stops
+ * @param <Z> the zoom function input type (Float usually)
+ * @param <I> the function input type for the source part of the function
+ * @param <O> the function output type
+ * @return the {@link CompositeFunction}
+ * @see CompositeFunction
+ * @see IntervalStops
+ * @see Stops#interval(Stop[])
+ * @see Stop#stop
+ */
+ public static <Z extends Number, I, O> CompositeFunction<Z, I, O> composite(
+ @NonNull String property,
+ @NonNull IntervalStops<Stop.CompositeValue<Z, I>, O> stops) {
+
+ return new CompositeFunction<>(property, stops);
+ }
+
+ // Class definition //
+
+ private final Stops<I, O> stops;
+
+ /**
+ * JNI Cosntructor for implementation classes
+ *
+ * @param stops the stops
+ */
+ Function(@NonNull Stops<I, O> stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * @return the stops in this function
+ */
+ public Stops getStops() {
+ return stops;
+ }
+
+ /**
+ * Convenience method
+ *
+ * @param <S> the Stops implementation type
+ * @return the Stops implementation or null when the wrong type is specified
+ */
+ @Nullable
+ public <S extends Stops> S getStopsAs() {
+ try {
+ // noinspection unchecked
+ return (S) stops;
+ } catch (ClassCastException exception) {
+ Timber.e(String.format("Stops: %s is a different type: %s", stops.getClass(), exception));
+ return null;
+ }
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return a value object representation for core conversion
+ */
+ public Map<String, Object> toValueObject() {
+ return stops.toValueObject();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s: %s", getClass().getSimpleName(), stops);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java
new file mode 100644
index 0000000000..f0eed760a4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/SourceFunction.java
@@ -0,0 +1,84 @@
+package com.mapbox.mapboxsdk.style.functions;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+
+import java.util.Map;
+
+/**
+ * Source functions take Feature property names as input.
+ * <p>
+ * Source functions allow the appearance of a map feature to change with
+ * its properties. Source functions can be used to visually differentiate
+ * types of features within the same layer or create data visualizations.
+ * Each stop is an array with two elements, the first is a property input
+ * value and the second is a function output value. Note that support for
+ * property functions is not available across all properties and platforms
+ * at this time.
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see Function#property
+ */
+public class SourceFunction<I, O> extends Function<I, O> {
+
+ private final String property;
+ private O defaultValue;
+
+ SourceFunction(@NonNull String property, @NonNull Stops<I, O> stops) {
+ this(null, property, stops);
+ }
+
+ /**
+ * JNI Constructor
+ */
+ private SourceFunction(@Nullable O defaultValue, @NonNull String property, @NonNull Stops<I, O> stops) {
+ super(stops);
+ this.property = property;
+ this.defaultValue = defaultValue;
+ }
+
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return The feature property name
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * Set the default value
+ *
+ * @param defaultValue the default value to use when no other applies
+ * @return this (for chaining)
+ */
+ public SourceFunction<I, O> withDefaultValue(O defaultValue) {
+ this.defaultValue = defaultValue;
+ return this;
+ }
+
+ /**
+ * @return the defaultValue
+ */
+ @Nullable
+ public O getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> valueObject = super.toValueObject();
+ valueObject.put(PROPERTY_KEY, property);
+ if (defaultValue != null) {
+ valueObject.put(DEFAULT_VALUE_KEY, defaultValue);
+ }
+ return valueObject;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java
new file mode 100644
index 0000000000..6979676c9e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains the Mapbox Maps Android Style Function API classes.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+package com.mapbox.mapboxsdk.style.functions;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java
new file mode 100644
index 0000000000..f9b2929350
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops.java
@@ -0,0 +1,64 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * {@link Stops} implementation for categorical functions
+ *
+ * @param <I> the {@link Stop} input type
+ * @param <O> the {@link Stop} output type
+ */
+public class CategoricalStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private final Stop<I, O>[] stops;
+
+ /**
+ * Create a categorical {@link Stops} implementation. Use through {@link Stops#categorical(Stop[])}
+ *
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public CategoricalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "categorical";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java
new file mode 100644
index 0000000000..d47aa1fc91
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops.java
@@ -0,0 +1,97 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The {@link Stops} implementation for exponential functions
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ */
+public class ExponentialStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private float base;
+ private final Stop<I, O>[] stops;
+
+ /**
+ * Create exponential stops with an explicit base. Use through {@link Stops#exponential(Stop[])}
+ *
+ * @param base The exponential base of the interpolation curve. It controls the rate at which the function output
+ * increases. Higher values make the output increase more towards the high end of the range.
+ * With values close to 1 the output increases linearly.
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public ExponentialStops(Float base, @NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.base = base != null ? base : 1.0f;
+ this.stops = stops;
+ }
+
+ /**
+ * Create exponential stops without an explicit base. Use through {@link Stops#exponential(Stop[])}
+ *
+ * @param stops the stops
+ */
+ @SafeVarargs
+ public ExponentialStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this(null, stops);
+ }
+
+ /**
+ * Set the exponential base
+ *
+ * @param base the base to use in the exponential function
+ * @return this (for chaining)
+ */
+ public ExponentialStops<I, O> withBase(float base) {
+ this.base = base;
+ return this;
+ }
+
+ /**
+ * @return The exponential base
+ */
+ public float getBase() {
+ return base;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("base", base);
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "exponential";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java
new file mode 100644
index 0000000000..2c0b198dc2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IdentityStops.java
@@ -0,0 +1,18 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+/**
+ * The {@link Stops} implementation for identity functions
+ *
+ * @param <T> the input/output type
+ */
+public class IdentityStops<T> extends Stops<T, T> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected String getTypeName() {
+ return "identity";
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java
new file mode 100644
index 0000000000..9d95b3f8c1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IntervalStops.java
@@ -0,0 +1,58 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * The {@link Stops} implementation for interval functions
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ */
+public class IntervalStops<I, O> extends IterableStops<I, O, Stop<I, O>> {
+
+ private final Stop<I, O>[] stops;
+
+ @SafeVarargs
+ public IntervalStops(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ this.stops = stops;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getTypeName() {
+ return "interval";
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Object> toValueObject() {
+ Map<String, Object> map = super.toValueObject();
+ map.put("stops", toValueObjects(stops));
+ return map;
+ }
+
+ /**
+ * @return an {@link Iterator} for the contained stops
+ */
+ @Override
+ public Iterator<Stop<I, O>> iterator() {
+ return Arrays.asList(stops).iterator();
+ }
+
+ /**
+ * @return The number of contained stops
+ */
+ @Override
+ public int size() {
+ return stops.length;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java
new file mode 100644
index 0000000000..8c5a6e8913
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/IterableStops.java
@@ -0,0 +1,52 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import java.util.Iterator;
+
+/**
+ * Base class for {@link Stops} implementations with a collection of stops
+ *
+ * @param <I> the {@link Stops} input type
+ * @param <O> the {@link Stops} output type
+ * @param <S> the {@link Iterable} element type (usually {@link Stop})
+ */
+public abstract class IterableStops<I, O, S> extends Stops<I, O> implements Iterable<S> {
+
+ /**
+ * @return The size of the contained stops collection
+ */
+ public abstract int size();
+
+ /**
+ * Convenience function to toValueObjects an array of stops to an array of value objects
+ *
+ * @param stops the stops to toValueObjects
+ * @return the stops as value objects
+ */
+ Object[] toValueObjects(Stop<I, O>[] stops) {
+ if (stops != null) {
+ Object[] stopsValue = new Object[stops.length];
+
+ for (int i = 0; i < stopsValue.length; i++) {
+ Stop stop = stops[i];
+ stopsValue[i] = stop.toValueObject();
+ }
+ return stopsValue;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ Iterator<S> iterator = iterator();
+ while (iterator.hasNext()) {
+ S stop = iterator.next();
+ buffer.append(stop);
+ if (iterator.hasNext()) {
+ buffer.append(",");
+ }
+ }
+ return String.format("%s: [%s]", super.toString(), buffer.toString());
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java
new file mode 100644
index 0000000000..72164f4c4b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stop.java
@@ -0,0 +1,109 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.layers.PropertyValue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A stop represents a certain point in the range of this function
+ *
+ * @param <I> input the stop (function) input type
+ * @param <O> output the stop (function) output type
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public class Stop<I, O> {
+ /**
+ * Creates a {@link Stop} to use in a {@link Function}
+ *
+ * @param in the input for the stop
+ * @param output the output for the stop
+ * @param <I> the input property type
+ * @param <O> the output property type
+ * @return the {@link Stop}
+ */
+ public static <I, O> Stop<I, O> stop(I in, PropertyValue<O> output) {
+ return new Stop<>(in, output.value);
+ }
+
+ /**
+ * Create a composite {@link Stop} for use in a {@link com.mapbox.mapboxsdk.style.functions.CompositeFunction}
+ *
+ * @param zoom the zoom input
+ * @param value the feature property input
+ * @param output the output for the stop
+ * @param <Z> the zoom type
+ * @param <I> the feature property input type
+ * @param <O> the output property type
+ * @return the {@link Stop}
+ * @see Function#composite(String, ExponentialStops)
+ */
+ public static <Z extends Number, I, O> Stop<Stop.CompositeValue<Z, I>, O> stop(Z zoom,
+ I value,
+ PropertyValue<O> output) {
+ return new Stop<>(new Stop.CompositeValue<>(zoom, value), output.value);
+ }
+
+ /**
+ * Represents a composite input value for composite functions (eg zoom and feature property value)
+ *
+ * @param <Z> the zoom input type (typically Float)
+ * @param <V> the feature property input type
+ */
+ public static class CompositeValue<Z extends Number, V> {
+ public final Z zoom;
+ public final V value;
+
+ CompositeValue(Z zoom, V value) {
+ this.zoom = zoom;
+ this.value = value;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the value object representation for core conversion
+ */
+ Map<String, Object> toValueObject() {
+ HashMap<String, Object> map = new HashMap<>();
+ map.put("zoom", zoom);
+ map.put("value", value);
+ return map;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[zoom: %s, value: %s]", zoom, value);
+ }
+ }
+
+ /**
+ * The input type
+ */
+ public final I in;
+
+ /**
+ * The output type
+ */
+ public final O out;
+
+ Stop(I in, O out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return an array representation of the Stop
+ */
+ Object[] toValueObject() {
+ return new Object[] {in instanceof CompositeValue ? ((CompositeValue) in).toValueObject() : in, out};
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%s, %s]", in, out);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java
new file mode 100644
index 0000000000..af4f53c072
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/Stops.java
@@ -0,0 +1,99 @@
+package com.mapbox.mapboxsdk.style.functions.stops;
+
+import android.support.annotation.CallSuper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Size;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The base class for different stops implementations
+ *
+ * @param <I> the input type
+ * @param <O> the output type
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+public abstract class Stops<I, O> {
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see CategoricalStops
+ */
+ @SafeVarargs
+ public static <I, O> CategoricalStops<I, O> categorical(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new CategoricalStops<>(stops);
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see ExponentialStops
+ */
+ @SafeVarargs
+ public static <I, O> ExponentialStops<I, O> exponential(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new ExponentialStops<>(stops);
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param <T> the Stops input/output type
+ * @return the {@link IdentityStops} implementation
+ * @see Stop#stop
+ * @see IdentityStops
+ */
+ public static <T> IdentityStops<T> identity() {
+ return new IdentityStops<>();
+ }
+
+ /**
+ * Convenience method for use in function declarations
+ *
+ * @param stops the collections of discrete stops
+ * @param <I> the Stops input type
+ * @param <O> the Stops output type
+ * @return the {@link Stops} implementation
+ * @see Stop#stop
+ * @see IntervalStops
+ */
+ @SafeVarargs
+ public static <I, O> IntervalStops<I, O> interval(@NonNull @Size(min = 1) Stop<I, O>... stops) {
+ return new IntervalStops<>(stops);
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the value object representation for conversion to core
+ */
+ @CallSuper
+ public Map<String, Object> toValueObject() {
+ HashMap<String, Object> map = new HashMap<>();
+ map.put("type", getTypeName());
+ return map;
+ }
+
+ /**
+ * INTERNAL USAGE ONLY
+ *
+ * @return the unique type name as a string according to the style specification
+ */
+ protected abstract String getTypeName();
+
+ @Override
+ public String toString() {
+ return getTypeName();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java
new file mode 100644
index 0000000000..fa388a9589
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/stops/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Contains the Mapbox Maps Android Style Function Stop implementation API classes.
+ *
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The style specification</a>
+ */
+package com.mapbox.mapboxsdk.style.functions.stops;
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 45523b41ab..0f1265f1a1 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
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
@@ -41,7 +42,7 @@ public class BackgroundLayer extends Layer {
* @param properties the var-args properties
* @return This
*/
- public BackgroundLayer withProperties(@NonNull Property<?>... properties) {
+ public BackgroundLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -55,7 +56,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getBackgroundColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetBackgroundColor());
+ return (PropertyValue<String>) new PropertyValue("background-color", nativeGetBackgroundColor());
}
/**
@@ -82,7 +83,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getBackgroundPattern() {
- return (PropertyValue<String>) new PropertyValue(nativeGetBackgroundPattern());
+ return (PropertyValue<String>) new PropertyValue("background-pattern", nativeGetBackgroundPattern());
}
/**
@@ -92,7 +93,7 @@ public class BackgroundLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getBackgroundOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetBackgroundOpacity());
+ return (PropertyValue<Float>) new PropertyValue("background-opacity", nativeGetBackgroundOpacity());
}
private native Object nativeGetBackgroundColor();
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 f16ab688d6..43ec255e81 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
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
@@ -62,27 +63,7 @@ public class CircleLayer extends Layer {
* @param filter the filter to set
*/
public void setFilter(Filter.Statement filter) {
- this.setFilter(filter.toArray());
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter the filter array to set
- */
- public void setFilter(Object[] filter) {
- nativeSetFilter(filter);
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter tthe filter array to set
- * @return This
- */
- public CircleLayer withFilter(Object[] filter) {
- setFilter(filter);
- return this;
+ nativeSetFilter(filter.toArray());
}
/**
@@ -96,14 +77,13 @@ public class CircleLayer extends Layer {
return this;
}
-
/**
* Set a property or properties.
*
* @param properties the var-args properties
* @return This
*/
- public CircleLayer withProperties(@NonNull Property<?>... properties) {
+ public CircleLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -117,7 +97,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleRadius() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetCircleRadius());
+ return (PropertyValue<Float>) new PropertyValue("circle-radius", nativeGetCircleRadius());
}
/**
@@ -127,7 +107,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetCircleColor());
+ return (PropertyValue<String>) new PropertyValue("circle-color", nativeGetCircleColor());
}
/**
@@ -154,7 +134,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleBlur() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetCircleBlur());
+ return (PropertyValue<Float>) new PropertyValue("circle-blur", nativeGetCircleBlur());
}
/**
@@ -164,7 +144,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetCircleOpacity());
+ return (PropertyValue<Float>) new PropertyValue("circle-opacity", nativeGetCircleOpacity());
}
/**
@@ -174,7 +154,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getCircleTranslate() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetCircleTranslate());
+ return (PropertyValue<Float[]>) new PropertyValue("circle-translate", nativeGetCircleTranslate());
}
/**
@@ -184,7 +164,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleTranslateAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetCircleTranslateAnchor());
+ return (PropertyValue<String>) new PropertyValue("circle-translate-anchor", nativeGetCircleTranslateAnchor());
}
/**
@@ -194,7 +174,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCirclePitchScale() {
- return (PropertyValue<String>) new PropertyValue(nativeGetCirclePitchScale());
+ return (PropertyValue<String>) new PropertyValue("circle-pitch-scale", nativeGetCirclePitchScale());
}
/**
@@ -204,7 +184,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleStrokeWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetCircleStrokeWidth());
+ return (PropertyValue<Float>) new PropertyValue("circle-stroke-width", nativeGetCircleStrokeWidth());
}
/**
@@ -214,7 +194,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getCircleStrokeColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetCircleStrokeColor());
+ return (PropertyValue<String>) new PropertyValue("circle-stroke-color", nativeGetCircleStrokeColor());
}
/**
@@ -241,7 +221,7 @@ public class CircleLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getCircleStrokeOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetCircleStrokeOpacity());
+ return (PropertyValue<Float>) new PropertyValue("circle-stroke-opacity", nativeGetCircleStrokeOpacity());
}
private native Object nativeGetCircleRadius();
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 3f79c9306a..8989f3a2ec 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
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
@@ -62,27 +63,7 @@ public class FillLayer extends Layer {
* @param filter the filter to set
*/
public void setFilter(Filter.Statement filter) {
- this.setFilter(filter.toArray());
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter the filter array to set
- */
- public void setFilter(Object[] filter) {
- nativeSetFilter(filter);
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter tthe filter array to set
- * @return This
- */
- public FillLayer withFilter(Object[] filter) {
- setFilter(filter);
- return this;
+ nativeSetFilter(filter.toArray());
}
/**
@@ -96,14 +77,13 @@ public class FillLayer extends Layer {
return this;
}
-
/**
* Set a property or properties.
*
* @param properties the var-args properties
* @return This
*/
- public FillLayer withProperties(@NonNull Property<?>... properties) {
+ public FillLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -117,7 +97,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getFillAntialias() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetFillAntialias());
+ return (PropertyValue<Boolean>) new PropertyValue("fill-antialias", nativeGetFillAntialias());
}
/**
@@ -127,7 +107,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getFillOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetFillOpacity());
+ return (PropertyValue<Float>) new PropertyValue("fill-opacity", nativeGetFillOpacity());
}
/**
@@ -137,12 +117,11 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetFillColor());
+ return (PropertyValue<String>) new PropertyValue("fill-color", nativeGetFillColor());
}
/**
- * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the
- * color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
*
* @return int representation of a rgba string color
* @throws RuntimeException thrown if property isn't a value
@@ -165,7 +144,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillOutlineColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetFillOutlineColor());
+ return (PropertyValue<String>) new PropertyValue("fill-outline-color", nativeGetFillOutlineColor());
}
/**
@@ -192,7 +171,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getFillTranslate() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetFillTranslate());
+ return (PropertyValue<Float[]>) new PropertyValue("fill-translate", nativeGetFillTranslate());
}
/**
@@ -202,7 +181,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillTranslateAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetFillTranslateAnchor());
+ return (PropertyValue<String>) new PropertyValue("fill-translate-anchor", nativeGetFillTranslateAnchor());
}
/**
@@ -212,7 +191,7 @@ public class FillLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getFillPattern() {
- return (PropertyValue<String>) new PropertyValue(nativeGetFillPattern());
+ return (PropertyValue<String>) new PropertyValue("fill-pattern", nativeGetFillPattern());
}
private native Object nativeGetFillAntialias();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java
deleted file mode 100644
index 900fe10476..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Function.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package com.mapbox.mapboxsdk.style.layers;
-
-import android.support.annotation.FloatRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.Size;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Functions are used to change properties in relation to the state of the map.
- * <p>
- * Currently, only zoom functions are supported.
- * </p>
- *
- * @param <T> the target property's value type. Make sure it matches.
- * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#types-function">The online documentation</a>
- */
-public class Function<T> {
-
- /**
- * A stop represents a certain point in the range of this function
- *
- * @param <I> input
- * @param <O> output
- */
- public static class Stop<I, O> {
- public final I in;
- public final O out;
-
- Stop(I in, O out) {
- this.in = in;
- this.out = out;
- }
-
- /**
- * @return an array representation of the Stop
- */
- Object[] toValueObject() {
- return new Object[] {in, out};
- }
-
- @Override
- public String toString() {
- return String.format("[%s, %s]", in, out);
- }
- }
-
- /**
- * Zoom functions allow the appearance of a map feature to change with map’s zoom.
- * Zoom functions can be used to create the illusion of depth and control data density.
- * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
- *
- * @param stops the stops that define the function
- * @param <T> the property type
- * @return the {@link Function}
- */
- @SafeVarargs
- public static <T> Function<T> zoom(@NonNull @Size(min = 1) Stop<Float, T>... stops) {
- return new Function<T>(stops);
- }
-
-
- /**
- * Zoom functions allow the appearance of a map feature to change with map’s zoom.
- * Zoom functions can be used to create the illusion of depth and control data density.
- * Each stop is an array with two elements, the first is a zoom and the second is a function output value.
- *
- * @param stops the stops that define the function
- * @param base the exponential base of the interpolation curve - Default 1
- * @param <T> the property type
- * @return the {@link Function}
- */
- @SafeVarargs
- public static <T> Function<T> zoom(
- @FloatRange(from = 0, to = 1, fromInclusive = false, toInclusive = false) float base,
- @NonNull @Size(min = 1) Stop<Float, T>... stops) {
- return new Function<T>(stops)
- .withBase(base);
- }
-
- /**
- * Creates a stop to use in a {@link Function}
- *
- * @param in the input for the stop
- * @param output the output for the stop
- * @param <T> the output property type
- * @return the {@link Stop}
- */
- public static <T> Stop<Float, T> stop(float in, Property<T> output) {
- return new Stop<>(in, output.value);
- }
-
- private final Stop<Float, T>[] stops;
- private Float base;
-
- Function(@NonNull @Size(min = 1) Stop<Float, T>[] stops) {
- this.stops = stops;
- }
-
- Function<T> withBase(float base) {
- this.base = base;
- return this;
- }
-
- /**
- * @return the base
- */
- @Nullable
- public Float getBase() {
- return base;
- }
-
- /**
- * @return the stops in this function
- */
- public Stop<Float, T>[] getStops() {
- return stops;
- }
-
- Map<String, Object> toValueObject() {
- Object[] stopsValue = new Object[stops.length];
-
- for (int i = 0; i < stopsValue.length; i++) {
- Stop stop = stops[i];
- stopsValue[i] = stop.toValueObject();
- }
-
- Map<String, Object> value = new HashMap<>();
- if (base != null) {
- value.put("base", base);
- }
- value.put("stops", stopsValue);
- return value;
- }
-}
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 2878d76430..b4120f4f9a 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,6 +2,8 @@ package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.style.functions.Function;
+
/**
* Base class for the different Layer types
*/
@@ -17,14 +19,14 @@ public abstract class Layer {
public Layer() {
}
- public void setProperties(@NonNull Property<?>... properties) {
+ public void setProperties(@NonNull PropertyValue<?>... properties) {
if (properties.length == 0) {
return;
}
- for (Property<?> property : properties) {
+ for (PropertyValue<?> property : properties) {
Object converted = convertValue(property.value);
- if (property instanceof PaintProperty) {
+ if (property instanceof PaintPropertyValue) {
nativeSetPaintProperty(property.name, converted);
} else {
nativeSetLayoutProperty(property.name, converted);
@@ -37,7 +39,7 @@ public abstract class Layer {
}
public PropertyValue<String> getVisibility() {
- return new PropertyValue<>(nativeGetVisibility());
+ return new PaintPropertyValue<>("visibility", (String) nativeGetVisibility());
}
public float getMinZoom() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java
deleted file mode 100644
index 4c0b52be55..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutProperty.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.mapbox.mapboxsdk.style.layers;
-
-class LayoutProperty<T> extends Property<T> {
-
- LayoutProperty(String name, T value) {
- super(name, value);
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java
new file mode 100644
index 0000000000..ed88a85912
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LayoutPropertyValue.java
@@ -0,0 +1,11 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.NonNull;
+
+class LayoutPropertyValue<T> extends PropertyValue<T> {
+
+ LayoutPropertyValue(@NonNull String name, T value) {
+ super(name, value);
+ }
+
+}
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 4c52a40b05..6992c22ace 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
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
@@ -62,27 +63,7 @@ public class LineLayer extends Layer {
* @param filter the filter to set
*/
public void setFilter(Filter.Statement filter) {
- this.setFilter(filter.toArray());
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter the filter array to set
- */
- public void setFilter(Object[] filter) {
- nativeSetFilter(filter);
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter tthe filter array to set
- * @return This
- */
- public LineLayer withFilter(Object[] filter) {
- setFilter(filter);
- return this;
+ nativeSetFilter(filter.toArray());
}
/**
@@ -96,14 +77,13 @@ public class LineLayer extends Layer {
return this;
}
-
/**
* Set a property or properties.
*
* @param properties the var-args properties
* @return This
*/
- public LineLayer withProperties(@NonNull Property<?>... properties) {
+ public LineLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -117,7 +97,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineCap() {
- return (PropertyValue<String>) new PropertyValue(nativeGetLineCap());
+ return (PropertyValue<String>) new PropertyValue("line-cap", nativeGetLineCap());
}
/**
@@ -127,7 +107,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineJoin() {
- return (PropertyValue<String>) new PropertyValue(nativeGetLineJoin());
+ return (PropertyValue<String>) new PropertyValue("line-join", nativeGetLineJoin());
}
/**
@@ -137,7 +117,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineMiterLimit() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineMiterLimit());
+ return (PropertyValue<Float>) new PropertyValue("line-miter-limit", nativeGetLineMiterLimit());
}
/**
@@ -147,7 +127,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineRoundLimit() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineRoundLimit());
+ return (PropertyValue<Float>) new PropertyValue("line-round-limit", nativeGetLineRoundLimit());
}
/**
@@ -157,7 +137,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineOpacity());
+ return (PropertyValue<Float>) new PropertyValue("line-opacity", nativeGetLineOpacity());
}
/**
@@ -167,7 +147,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetLineColor());
+ return (PropertyValue<String>) new PropertyValue("line-color", nativeGetLineColor());
}
/**
@@ -194,7 +174,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getLineTranslate() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetLineTranslate());
+ return (PropertyValue<Float[]>) new PropertyValue("line-translate", nativeGetLineTranslate());
}
/**
@@ -204,7 +184,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLineTranslateAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetLineTranslateAnchor());
+ return (PropertyValue<String>) new PropertyValue("line-translate-anchor", nativeGetLineTranslateAnchor());
}
/**
@@ -214,7 +194,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineWidth());
+ return (PropertyValue<Float>) new PropertyValue("line-width", nativeGetLineWidth());
}
/**
@@ -224,7 +204,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineGapWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineGapWidth());
+ return (PropertyValue<Float>) new PropertyValue("line-gap-width", nativeGetLineGapWidth());
}
/**
@@ -234,7 +214,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineOffset() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineOffset());
+ return (PropertyValue<Float>) new PropertyValue("line-offset", nativeGetLineOffset());
}
/**
@@ -244,7 +224,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getLineBlur() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetLineBlur());
+ return (PropertyValue<Float>) new PropertyValue("line-blur", nativeGetLineBlur());
}
/**
@@ -254,7 +234,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getLineDasharray() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetLineDasharray());
+ return (PropertyValue<Float[]>) new PropertyValue("line-dasharray", nativeGetLineDasharray());
}
/**
@@ -264,7 +244,7 @@ public class LineLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getLinePattern() {
- return (PropertyValue<String>) new PropertyValue(nativeGetLinePattern());
+ return (PropertyValue<String>) new PropertyValue("line-pattern", nativeGetLinePattern());
}
private native Object nativeGetLineCap();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java
deleted file mode 100644
index 3b8777080d..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/NoSuchLayerException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.mapbox.mapboxsdk.style.layers;
-
-/**
- * No such layer.
- */
-public class NoSuchLayerException extends Exception {
-
- public NoSuchLayerException(String message) {
- super(message);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java
deleted file mode 100644
index 69405177d9..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintProperty.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.mapbox.mapboxsdk.style.layers;
-
-class PaintProperty<T> extends Property<T> {
-
- PaintProperty(String name, T value) {
- super(name, value);
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java
new file mode 100644
index 0000000000..e6ac2d9763
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PaintPropertyValue.java
@@ -0,0 +1,11 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.NonNull;
+
+class PaintPropertyValue<T> extends PropertyValue<T> {
+
+ PaintPropertyValue(@NonNull String name, T value) {
+ super(name, value);
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
index bb060ddf15..641ee551a2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.StringDef;
import java.lang.annotation.Retention;
@@ -9,9 +10,9 @@ import java.lang.annotation.RetentionPolicy;
/**
* Paint/Layout properties for Layer
*/
-public abstract class Property<T> {
+public final class Property {
- //VISIBILITY: Whether this layer is displayed.
+ // VISIBILITY: Whether this layer is displayed.
/**
* The layer is shown.
@@ -22,74 +23,66 @@ public abstract class Property<T> {
*/
public static final String NONE = "none";
- @StringDef( {
- VISIBLE,
- NONE
+ @StringDef({
+ VISIBLE,
+ NONE
})
@Retention(RetentionPolicy.SOURCE)
- public @interface VISIBILITY {
- }
+ public @interface VISIBILITY {}
- //LINE_CAP: The display of line endings.
+ // LINE_CAP: The display of line endings.
/**
* A cap with a squared-off end which is drawn to the exact endpoint of the line.
*/
public static final String LINE_CAP_BUTT = "butt";
/**
- * A cap with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's
- * width and centered on the endpoint of the line.
+ * A cap with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
*/
public static final String LINE_CAP_ROUND = "round";
/**
- * A cap with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the
- * line's width.
+ * A cap with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
*/
public static final String LINE_CAP_SQUARE = "square";
/**
* The display of line endings.
*/
- @StringDef( {
- LINE_CAP_BUTT,
- LINE_CAP_ROUND,
- LINE_CAP_SQUARE,
- })
+ @StringDef({
+ LINE_CAP_BUTT,
+ LINE_CAP_ROUND,
+ LINE_CAP_SQUARE,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface LINE_CAP {
- }
+ public @interface LINE_CAP {}
- //LINE_JOIN: The display of lines when joining.
+ // LINE_JOIN: The display of lines when joining.
/**
- * A join with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the
- * line's width.
+ * A join with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width.
*/
public static final String LINE_JOIN_BEVEL = "bevel";
/**
- * A join with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's
- * width and centered on the endpoint of the line.
+ * A join with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line.
*/
public static final String LINE_JOIN_ROUND = "round";
/**
- * A join with a sharp, angled corner which is drawn with the outer sides beyond the endpoint of the path until
- * they meet.
+ * A join with a sharp, angled corner which is drawn with the outer sides beyond the endpoint of the path until they meet.
*/
public static final String LINE_JOIN_MITER = "miter";
/**
* The display of lines when joining.
*/
- @StringDef( {
- LINE_JOIN_BEVEL,
- LINE_JOIN_ROUND,
- LINE_JOIN_MITER,
- })
+ @StringDef({
+ LINE_JOIN_BEVEL,
+ LINE_JOIN_ROUND,
+ LINE_JOIN_MITER,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface LINE_JOIN {
- }
+ public @interface LINE_JOIN {}
- //SYMBOL_PLACEMENT: Label placement relative to its geometry.
+ // SYMBOL_PLACEMENT: Label placement relative to its geometry.
/**
* The label is placed at the point where the geometry is located.
@@ -103,46 +96,40 @@ public abstract class Property<T> {
/**
* Label placement relative to its geometry.
*/
- @StringDef( {
- SYMBOL_PLACEMENT_POINT,
- SYMBOL_PLACEMENT_LINE,
- })
+ @StringDef({
+ SYMBOL_PLACEMENT_POINT,
+ SYMBOL_PLACEMENT_LINE,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface SYMBOL_PLACEMENT {
- }
+ public @interface SYMBOL_PLACEMENT {}
- //ICON_ROTATION_ALIGNMENT: In combination with `symbol-placement`, determines the rotation behavior of icons.
+ // ICON_ROTATION_ALIGNMENT: In combination with `symbol-placement`, determines the rotation behavior of icons.
/**
- * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, aligns icons east-west. When
- * {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, aligns icon x-axes with the line.
+ * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, aligns icons east-west. When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, aligns icon x-axes with the line.
*/
public static final String ICON_ROTATION_ALIGNMENT_MAP = "map";
/**
- * Produces icons whose x-axes are aligned with the x-axis of the viewport, regardless of the value of
- * {@link SYMBOL_PLACEMENT}.
+ * Produces icons whose x-axes are aligned with the x-axis of the viewport, regardless of the value of {@link SYMBOL_PLACEMENT}.
*/
public static final String ICON_ROTATION_ALIGNMENT_VIEWPORT = "viewport";
/**
- * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, this is equivalent to
- * {@link Property#ICON_ROTATION_ALIGNMENT_VIEWPORT}. When {@link SYMBOL_PLACEMENT} is set to
- * {@link Property#SYMBOL_PLACEMENT_LINE}, this is equivalent to {@link Property#ICON_ROTATION_ALIGNMENT_MAP}.
+ * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, this is equivalent to {@link Property#ICON_ROTATION_ALIGNMENT_VIEWPORT}. When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, this is equivalent to {@link Property#ICON_ROTATION_ALIGNMENT_MAP}.
*/
public static final String ICON_ROTATION_ALIGNMENT_AUTO = "auto";
/**
* In combination with `symbol-placement`, determines the rotation behavior of icons.
*/
- @StringDef( {
- ICON_ROTATION_ALIGNMENT_MAP,
- ICON_ROTATION_ALIGNMENT_VIEWPORT,
- ICON_ROTATION_ALIGNMENT_AUTO,
- })
+ @StringDef({
+ ICON_ROTATION_ALIGNMENT_MAP,
+ ICON_ROTATION_ALIGNMENT_VIEWPORT,
+ ICON_ROTATION_ALIGNMENT_AUTO,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface ICON_ROTATION_ALIGNMENT {
- }
+ public @interface ICON_ROTATION_ALIGNMENT {}
- //ICON_TEXT_FIT: Scales the icon to fit around the associated text.
+ // ICON_TEXT_FIT: Scales the icon to fit around the associated text.
/**
* The icon is displayed at its intrinsic aspect ratio.
@@ -164,17 +151,16 @@ public abstract class Property<T> {
/**
* Scales the icon to fit around the associated text.
*/
- @StringDef( {
- ICON_TEXT_FIT_NONE,
- ICON_TEXT_FIT_WIDTH,
- ICON_TEXT_FIT_HEIGHT,
- ICON_TEXT_FIT_BOTH,
- })
+ @StringDef({
+ ICON_TEXT_FIT_NONE,
+ ICON_TEXT_FIT_WIDTH,
+ ICON_TEXT_FIT_HEIGHT,
+ ICON_TEXT_FIT_BOTH,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface ICON_TEXT_FIT {
- }
+ public @interface ICON_TEXT_FIT {}
- //TEXT_PITCH_ALIGNMENT: Orientation of text when map is pitched.
+ // TEXT_PITCH_ALIGNMENT: Orientation of text when map is pitched.
/**
* The text is aligned to the plane of the map.
@@ -192,48 +178,41 @@ public abstract class Property<T> {
/**
* Orientation of text when map is pitched.
*/
- @StringDef( {
- TEXT_PITCH_ALIGNMENT_MAP,
- TEXT_PITCH_ALIGNMENT_VIEWPORT,
- TEXT_PITCH_ALIGNMENT_AUTO,
- })
+ @StringDef({
+ TEXT_PITCH_ALIGNMENT_MAP,
+ TEXT_PITCH_ALIGNMENT_VIEWPORT,
+ TEXT_PITCH_ALIGNMENT_AUTO,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_PITCH_ALIGNMENT {
- }
+ public @interface TEXT_PITCH_ALIGNMENT {}
- //TEXT_ROTATION_ALIGNMENT: In combination with `symbol-placement`, determines the rotation behavior of the individual
- // glyphs forming the text.
+ // TEXT_ROTATION_ALIGNMENT: In combination with `symbol-placement`, determines the rotation behavior of the individual glyphs forming the text.
/**
- * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, aligns text east-west. When
- * {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, aligns text x-axes with the line.
+ * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, aligns text east-west. When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, aligns text x-axes with the line.
*/
public static final String TEXT_ROTATION_ALIGNMENT_MAP = "map";
/**
- * Produces glyphs whose x-axes are aligned with the x-axis of the viewport, regardless of the value of
- * {@link SYMBOL_PLACEMENT}.
+ * Produces glyphs whose x-axes are aligned with the x-axis of the viewport, regardless of the value of {@link SYMBOL_PLACEMENT}.
*/
public static final String TEXT_ROTATION_ALIGNMENT_VIEWPORT = "viewport";
/**
- * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, this is equivalent to
- * {@link Property#TEXT_ROTATION_ALIGNMENT_VIEWPORT}. When {@link SYMBOL_PLACEMENT} is set to
- * {@link Property#SYMBOL_PLACEMENT_LINE}, this is equivalent to {@link Property#TEXT_ROTATION_ALIGNMENT_MAP}.
+ * When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_POINT}, this is equivalent to {@link Property#TEXT_ROTATION_ALIGNMENT_VIEWPORT}. When {@link SYMBOL_PLACEMENT} is set to {@link Property#SYMBOL_PLACEMENT_LINE}, this is equivalent to {@link Property#TEXT_ROTATION_ALIGNMENT_MAP}.
*/
public static final String TEXT_ROTATION_ALIGNMENT_AUTO = "auto";
/**
* In combination with `symbol-placement`, determines the rotation behavior of the individual glyphs forming the text.
*/
- @StringDef( {
- TEXT_ROTATION_ALIGNMENT_MAP,
- TEXT_ROTATION_ALIGNMENT_VIEWPORT,
- TEXT_ROTATION_ALIGNMENT_AUTO,
- })
+ @StringDef({
+ TEXT_ROTATION_ALIGNMENT_MAP,
+ TEXT_ROTATION_ALIGNMENT_VIEWPORT,
+ TEXT_ROTATION_ALIGNMENT_AUTO,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_ROTATION_ALIGNMENT {
- }
+ public @interface TEXT_ROTATION_ALIGNMENT {}
- //TEXT_JUSTIFY: Text justification options.
+ // TEXT_JUSTIFY: Text justification options.
/**
* The text is aligned to the left.
@@ -251,16 +230,15 @@ public abstract class Property<T> {
/**
* Text justification options.
*/
- @StringDef( {
- TEXT_JUSTIFY_LEFT,
- TEXT_JUSTIFY_CENTER,
- TEXT_JUSTIFY_RIGHT,
- })
+ @StringDef({
+ TEXT_JUSTIFY_LEFT,
+ TEXT_JUSTIFY_CENTER,
+ TEXT_JUSTIFY_RIGHT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_JUSTIFY {
- }
+ public @interface TEXT_JUSTIFY {}
- //TEXT_ANCHOR: Part of the text placed closest to the anchor.
+ // TEXT_ANCHOR: Part of the text placed closest to the anchor.
/**
* The center of the text is placed closest to the anchor.
@@ -302,22 +280,21 @@ public abstract class Property<T> {
/**
* Part of the text placed closest to the anchor.
*/
- @StringDef( {
- TEXT_ANCHOR_CENTER,
- TEXT_ANCHOR_LEFT,
- TEXT_ANCHOR_RIGHT,
- TEXT_ANCHOR_TOP,
- TEXT_ANCHOR_BOTTOM,
- TEXT_ANCHOR_TOP_LEFT,
- TEXT_ANCHOR_TOP_RIGHT,
- TEXT_ANCHOR_BOTTOM_LEFT,
- TEXT_ANCHOR_BOTTOM_RIGHT,
- })
+ @StringDef({
+ TEXT_ANCHOR_CENTER,
+ TEXT_ANCHOR_LEFT,
+ TEXT_ANCHOR_RIGHT,
+ TEXT_ANCHOR_TOP,
+ TEXT_ANCHOR_BOTTOM,
+ TEXT_ANCHOR_TOP_LEFT,
+ TEXT_ANCHOR_TOP_RIGHT,
+ TEXT_ANCHOR_BOTTOM_LEFT,
+ TEXT_ANCHOR_BOTTOM_RIGHT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_ANCHOR {
- }
+ public @interface TEXT_ANCHOR {}
- //TEXT_TRANSFORM: Specifies how to capitalize text, similar to the CSS `text-transform` property.
+ // TEXT_TRANSFORM: Specifies how to capitalize text, similar to the CSS `text-transform` property.
/**
* The text is not altered.
@@ -335,16 +312,15 @@ public abstract class Property<T> {
/**
* Specifies how to capitalize text, similar to the CSS `text-transform` property.
*/
- @StringDef( {
- TEXT_TRANSFORM_NONE,
- TEXT_TRANSFORM_UPPERCASE,
- TEXT_TRANSFORM_LOWERCASE,
- })
+ @StringDef({
+ TEXT_TRANSFORM_NONE,
+ TEXT_TRANSFORM_UPPERCASE,
+ TEXT_TRANSFORM_LOWERCASE,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_TRANSFORM {
- }
+ public @interface TEXT_TRANSFORM {}
- //FILL_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // FILL_TRANSLATE_ANCHOR: Controls the translation reference point.
/**
* The fill is translated relative to the map.
@@ -358,15 +334,14 @@ public abstract class Property<T> {
/**
* Controls the translation reference point.
*/
- @StringDef( {
- FILL_TRANSLATE_ANCHOR_MAP,
- FILL_TRANSLATE_ANCHOR_VIEWPORT,
- })
+ @StringDef({
+ FILL_TRANSLATE_ANCHOR_MAP,
+ FILL_TRANSLATE_ANCHOR_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface FILL_TRANSLATE_ANCHOR {
- }
+ public @interface FILL_TRANSLATE_ANCHOR {}
- //LINE_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // LINE_TRANSLATE_ANCHOR: Controls the translation reference point.
/**
* The line is translated relative to the map.
@@ -380,15 +355,14 @@ public abstract class Property<T> {
/**
* Controls the translation reference point.
*/
- @StringDef( {
- LINE_TRANSLATE_ANCHOR_MAP,
- LINE_TRANSLATE_ANCHOR_VIEWPORT,
- })
+ @StringDef({
+ LINE_TRANSLATE_ANCHOR_MAP,
+ LINE_TRANSLATE_ANCHOR_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface LINE_TRANSLATE_ANCHOR {
- }
+ public @interface LINE_TRANSLATE_ANCHOR {}
- //ICON_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // ICON_TRANSLATE_ANCHOR: Controls the translation reference point.
/**
* Icons are translated relative to the map.
@@ -402,15 +376,14 @@ public abstract class Property<T> {
/**
* Controls the translation reference point.
*/
- @StringDef( {
- ICON_TRANSLATE_ANCHOR_MAP,
- ICON_TRANSLATE_ANCHOR_VIEWPORT,
- })
+ @StringDef({
+ ICON_TRANSLATE_ANCHOR_MAP,
+ ICON_TRANSLATE_ANCHOR_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface ICON_TRANSLATE_ANCHOR {
- }
+ public @interface ICON_TRANSLATE_ANCHOR {}
- //TEXT_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // TEXT_TRANSLATE_ANCHOR: Controls the translation reference point.
/**
* The text is translated relative to the map.
@@ -424,15 +397,14 @@ public abstract class Property<T> {
/**
* Controls the translation reference point.
*/
- @StringDef( {
- TEXT_TRANSLATE_ANCHOR_MAP,
- TEXT_TRANSLATE_ANCHOR_VIEWPORT,
- })
+ @StringDef({
+ TEXT_TRANSLATE_ANCHOR_MAP,
+ TEXT_TRANSLATE_ANCHOR_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface TEXT_TRANSLATE_ANCHOR {
- }
+ public @interface TEXT_TRANSLATE_ANCHOR {}
- //CIRCLE_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // CIRCLE_TRANSLATE_ANCHOR: Controls the translation reference point.
/**
* The circle is translated relative to the map.
@@ -446,15 +418,14 @@ public abstract class Property<T> {
/**
* Controls the translation reference point.
*/
- @StringDef( {
- CIRCLE_TRANSLATE_ANCHOR_MAP,
- CIRCLE_TRANSLATE_ANCHOR_VIEWPORT,
- })
+ @StringDef({
+ CIRCLE_TRANSLATE_ANCHOR_MAP,
+ CIRCLE_TRANSLATE_ANCHOR_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface CIRCLE_TRANSLATE_ANCHOR {
- }
+ public @interface CIRCLE_TRANSLATE_ANCHOR {}
- //CIRCLE_PITCH_SCALE: Controls the scaling behavior of the circle when the map is pitched.
+ // CIRCLE_PITCH_SCALE: Controls the scaling behavior of the circle when the map is pitched.
/**
* Circles are scaled according to their apparent distance to the camera.
@@ -468,20 +439,14 @@ public abstract class Property<T> {
/**
* Controls the scaling behavior of the circle when the map is pitched.
*/
- @StringDef( {
- CIRCLE_PITCH_SCALE_MAP,
- CIRCLE_PITCH_SCALE_VIEWPORT,
- })
+ @StringDef({
+ CIRCLE_PITCH_SCALE_MAP,
+ CIRCLE_PITCH_SCALE_VIEWPORT,
+ })
@Retention(RetentionPolicy.SOURCE)
- public @interface CIRCLE_PITCH_SCALE {
- }
+ public @interface CIRCLE_PITCH_SCALE {}
- //Class definition
- public final String name;
- public final T value;
- /* package */ Property(String name, T value) {
- this.name = name;
- this.value = value;
+ private Property() {
}
}
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 8e7d516a39..5cd0d99270 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
@@ -1,9 +1,13 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.annotation.SuppressLint;
import android.support.annotation.ColorInt;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+
/**
* Constructs paint/layout properties for Layers
*
@@ -17,18 +21,19 @@ public class PropertyFactory {
* @param value the visibility value
* @return property wrapper around visibility
*/
- public static Property<String> visibility(@Property.VISIBILITY String value) {
- return new LayoutProperty<>("visibility", value);
+ public static PropertyValue<String> visibility(@Property.VISIBILITY String value) {
+ return new LayoutPropertyValue<>("visibility", value);
}
/**
* Set the property visibility.
*
+ * @param <T> the function input type
* @param function the visibility function
* @return property wrapper around a String function
*/
- public static Property<Function<String>> visibility(Function<String> function) {
- return new LayoutProperty<>("visibility", function);
+ public static <T> PropertyValue<Function<T, String>> visibility(Function<T, String> function) {
+ return new LayoutPropertyValue<>("visibility", function);
}
/**
@@ -37,73 +42,74 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> fillAntialias(Boolean value) {
- return new PaintProperty<>("fill-antialias", value);
+ public static PropertyValue<Boolean> fillAntialias(Boolean value) {
+ return new PaintPropertyValue<>("fill-antialias", value);
}
+
/**
* Whether or not the fill should be antialiased.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> fillAntialias(Function<Boolean> function) {
- return new PaintProperty<>("fill-antialias", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> fillAntialias(CameraFunction<Z, Boolean> function) {
+ return new PaintPropertyValue<>("fill-antialias", function);
}
/**
- * The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also
- * affect the 1px stroke around the fill, if the stroke is used.
+ * The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also affect the 1px stroke around the fill, if the stroke is used.
*
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> fillOpacity(Float value) {
- return new PaintProperty<>("fill-opacity", value);
+ public static PropertyValue<Float> fillOpacity(Float value) {
+ return new PaintPropertyValue<>("fill-opacity", value);
}
+
/**
- * The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also
- * affect the 1px stroke around the fill, if the stroke is used.
+ * The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also affect the 1px stroke around the fill, if the stroke is used.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> fillOpacity(Function<Float> function) {
- return new PaintProperty<>("fill-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> fillOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("fill-opacity", function);
}
/**
- * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the
- * color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
*
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> fillColor(@ColorInt int value) {
- return new PaintProperty<>("fill-color", colorToRgbaString(value));
+ public static PropertyValue<String> fillColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("fill-color", colorToRgbaString(value));
}
/**
- * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the
- * color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> fillColor(String value) {
- return new PaintProperty<>("fill-color", value);
+ public static PropertyValue<String> fillColor(String value) {
+ return new PaintPropertyValue<>("fill-color", value);
}
+
/**
- * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the
- * color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> fillColor(Function<String> function) {
- return new PaintProperty<>("fill-color", function);
+ public static <T> PropertyValue<Function<T, String>> fillColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("fill-color", function);
}
/**
@@ -112,8 +118,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> fillOutlineColor(@ColorInt int value) {
- return new PaintProperty<>("fill-outline-color", colorToRgbaString(value));
+ public static PropertyValue<String> fillOutlineColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("fill-outline-color", colorToRgbaString(value));
}
/**
@@ -122,18 +128,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> fillOutlineColor(String value) {
- return new PaintProperty<>("fill-outline-color", value);
+ public static PropertyValue<String> fillOutlineColor(String value) {
+ return new PaintPropertyValue<>("fill-outline-color", value);
}
+
/**
* The outline color of the fill. Matches the value of {@link PropertyFactory#fillColor} if unspecified.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> fillOutlineColor(Function<String> function) {
- return new PaintProperty<>("fill-outline-color", function);
+ public static <T> PropertyValue<Function<T, String>> fillOutlineColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("fill-outline-color", function);
}
/**
@@ -142,18 +150,20 @@ public class PropertyFactory {
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> fillTranslate(Float[] value) {
- return new PaintProperty<>("fill-translate", value);
+ public static PropertyValue<Float[]> fillTranslate(Float[] value) {
+ return new PaintPropertyValue<>("fill-translate", value);
}
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> fillTranslate(Function<Float[]> function) {
- return new PaintProperty<>("fill-translate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> fillTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("fill-translate", function);
}
/**
@@ -162,40 +172,42 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> fillTranslateAnchor(@Property.FILL_TRANSLATE_ANCHOR String value) {
- return new PaintProperty<>("fill-translate-anchor", value);
+ public static PropertyValue<String> fillTranslateAnchor(@Property.FILL_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("fill-translate-anchor", value);
}
+
/**
* Controls the translation reference point.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> fillTranslateAnchor(Function<String> function) {
- return new PaintProperty<>("fill-translate-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("fill-translate-anchor", function);
}
/**
- * 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).
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> fillPattern(String value) {
- return new PaintProperty<>("fill-pattern", value);
+ public static PropertyValue<String> fillPattern(String value) {
+ return new PaintPropertyValue<>("fill-pattern", value);
}
+
/**
- * 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).
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> fillPattern(Function<String> function) {
- return new PaintProperty<>("fill-pattern", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillPattern(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("fill-pattern", function);
}
/**
@@ -204,18 +216,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineOpacity(Float value) {
- return new PaintProperty<>("line-opacity", value);
+ public static PropertyValue<Float> lineOpacity(Float value) {
+ return new PaintPropertyValue<>("line-opacity", value);
}
+
/**
* The opacity at which the line will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineOpacity(Function<Float> function) {
- return new PaintProperty<>("line-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> lineOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("line-opacity", function);
}
/**
@@ -224,8 +238,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> lineColor(@ColorInt int value) {
- return new PaintProperty<>("line-color", colorToRgbaString(value));
+ public static PropertyValue<String> lineColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("line-color", colorToRgbaString(value));
}
/**
@@ -234,18 +248,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> lineColor(String value) {
- return new PaintProperty<>("line-color", value);
+ public static PropertyValue<String> lineColor(String value) {
+ return new PaintPropertyValue<>("line-color", value);
}
+
/**
* The color with which the line will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> lineColor(Function<String> function) {
- return new PaintProperty<>("line-color", function);
+ public static <T> PropertyValue<Function<T, String>> lineColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("line-color", function);
}
/**
@@ -254,18 +270,20 @@ public class PropertyFactory {
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> lineTranslate(Float[] value) {
- return new PaintProperty<>("line-translate", value);
+ public static PropertyValue<Float[]> lineTranslate(Float[] value) {
+ return new PaintPropertyValue<>("line-translate", value);
}
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> lineTranslate(Function<Float[]> function) {
- return new PaintProperty<>("line-translate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> lineTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("line-translate", function);
}
/**
@@ -274,18 +292,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> lineTranslateAnchor(@Property.LINE_TRANSLATE_ANCHOR String value) {
- return new PaintProperty<>("line-translate-anchor", value);
+ public static PropertyValue<String> lineTranslateAnchor(@Property.LINE_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("line-translate-anchor", value);
}
+
/**
* Controls the translation reference point.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> lineTranslateAnchor(Function<String> function) {
- return new PaintProperty<>("line-translate-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> lineTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("line-translate-anchor", function);
}
/**
@@ -294,18 +314,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineWidth(Float value) {
- return new PaintProperty<>("line-width", value);
+ public static PropertyValue<Float> lineWidth(Float value) {
+ return new PaintPropertyValue<>("line-width", value);
}
+
/**
* Stroke thickness.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineWidth(Function<Float> function) {
- return new PaintProperty<>("line-width", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> lineWidth(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("line-width", function);
}
/**
@@ -314,106 +336,108 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineGapWidth(Float value) {
- return new PaintProperty<>("line-gap-width", value);
+ public static PropertyValue<Float> lineGapWidth(Float value) {
+ return new PaintPropertyValue<>("line-gap-width", value);
}
+
/**
* Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineGapWidth(Function<Float> function) {
- return new PaintProperty<>("line-gap-width", function);
+ public static <T> PropertyValue<Function<T, Float>> lineGapWidth(Function<T, Float> function) {
+ return new PaintPropertyValue<>("line-gap-width", function);
}
/**
- * The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction
- * of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a
- * negative value results in an outset.
+ * The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
*
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineOffset(Float value) {
- return new PaintProperty<>("line-offset", value);
+ public static PropertyValue<Float> lineOffset(Float value) {
+ return new PaintPropertyValue<>("line-offset", value);
}
+
/**
- * The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction
- * of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a
- * negative value results in an outset.
+ * The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineOffset(Function<Float> function) {
- return new PaintProperty<>("line-offset", function);
+ public static <T> PropertyValue<Function<T, Float>> lineOffset(Function<T, Float> function) {
+ return new PaintPropertyValue<>("line-offset", function);
}
/**
- * Blur applied to the line, in pixels.
+ * Blur applied to the line, in density-independent pixels.
*
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineBlur(Float value) {
- return new PaintProperty<>("line-blur", value);
+ public static PropertyValue<Float> lineBlur(Float value) {
+ return new PaintPropertyValue<>("line-blur", value);
}
+
/**
- * Blur applied to the line, in pixels.
+ * Blur applied to the line, in density-independent pixels.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineBlur(Function<Float> function) {
- return new PaintProperty<>("line-blur", function);
+ public static <T> PropertyValue<Function<T, Float>> lineBlur(Function<T, Float> function) {
+ return new PaintPropertyValue<>("line-blur", function);
}
/**
- * 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 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.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> lineDasharray(Float[] value) {
- return new PaintProperty<>("line-dasharray", value);
+ public static PropertyValue<Float[]> lineDasharray(Float[] value) {
+ return new PaintPropertyValue<>("line-dasharray", value);
}
+
/**
- * 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 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.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> lineDasharray(Function<Float[]> function) {
- return new PaintProperty<>("line-dasharray", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> lineDasharray(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("line-dasharray", function);
}
/**
- * 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).
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> linePattern(String value) {
- return new PaintProperty<>("line-pattern", value);
+ public static PropertyValue<String> linePattern(String value) {
+ return new PaintPropertyValue<>("line-pattern", value);
}
+
/**
- * 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).
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> linePattern(Function<String> function) {
- return new PaintProperty<>("line-pattern", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> linePattern(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("line-pattern", function);
}
/**
@@ -422,18 +446,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconOpacity(Float value) {
- return new PaintProperty<>("icon-opacity", value);
+ public static PropertyValue<Float> iconOpacity(Float value) {
+ return new PaintPropertyValue<>("icon-opacity", value);
}
+
/**
* The opacity at which the icon will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconOpacity(Function<Float> function) {
- return new PaintProperty<>("icon-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> iconOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("icon-opacity", function);
}
/**
@@ -442,8 +468,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> iconColor(@ColorInt int value) {
- return new PaintProperty<>("icon-color", colorToRgbaString(value));
+ public static PropertyValue<String> iconColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("icon-color", colorToRgbaString(value));
}
/**
@@ -452,18 +478,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconColor(String value) {
- return new PaintProperty<>("icon-color", value);
+ public static PropertyValue<String> iconColor(String value) {
+ return new PaintPropertyValue<>("icon-color", value);
}
+
/**
* The color of the icon. This can only be used with sdf icons.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconColor(Function<String> function) {
- return new PaintProperty<>("icon-color", function);
+ public static <T> PropertyValue<Function<T, String>> iconColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("icon-color", function);
}
/**
@@ -472,8 +500,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> iconHaloColor(@ColorInt int value) {
- return new PaintProperty<>("icon-halo-color", colorToRgbaString(value));
+ public static PropertyValue<String> iconHaloColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("icon-halo-color", colorToRgbaString(value));
}
/**
@@ -482,18 +510,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconHaloColor(String value) {
- return new PaintProperty<>("icon-halo-color", value);
+ public static PropertyValue<String> iconHaloColor(String value) {
+ return new PaintPropertyValue<>("icon-halo-color", value);
}
+
/**
* The color of the icon's halo. Icon halos can only be used with SDF icons.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconHaloColor(Function<String> function) {
- return new PaintProperty<>("icon-halo-color", function);
+ public static <T> PropertyValue<Function<T, String>> iconHaloColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("icon-halo-color", function);
}
/**
@@ -502,18 +532,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconHaloWidth(Float value) {
- return new PaintProperty<>("icon-halo-width", value);
+ public static PropertyValue<Float> iconHaloWidth(Float value) {
+ return new PaintPropertyValue<>("icon-halo-width", value);
}
+
/**
* Distance of halo to the icon outline.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconHaloWidth(Function<Float> function) {
- return new PaintProperty<>("icon-halo-width", function);
+ public static <T> PropertyValue<Function<T, Float>> iconHaloWidth(Function<T, Float> function) {
+ return new PaintPropertyValue<>("icon-halo-width", function);
}
/**
@@ -522,40 +554,42 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconHaloBlur(Float value) {
- return new PaintProperty<>("icon-halo-blur", value);
+ public static PropertyValue<Float> iconHaloBlur(Float value) {
+ return new PaintPropertyValue<>("icon-halo-blur", value);
}
+
/**
* Fade out the halo towards the outside.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconHaloBlur(Function<Float> function) {
- return new PaintProperty<>("icon-halo-blur", function);
+ public static <T> PropertyValue<Function<T, Float>> iconHaloBlur(Function<T, Float> function) {
+ return new PaintPropertyValue<>("icon-halo-blur", function);
}
/**
- * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down,
- * while negative values indicate left and up.
+ * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> iconTranslate(Float[] value) {
- return new PaintProperty<>("icon-translate", value);
+ public static PropertyValue<Float[]> iconTranslate(Float[] value) {
+ return new PaintPropertyValue<>("icon-translate", value);
}
+
/**
- * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down,
- * while negative values indicate left and up.
+ * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> iconTranslate(Function<Float[]> function) {
- return new PaintProperty<>("icon-translate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> iconTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("icon-translate", function);
}
/**
@@ -564,18 +598,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconTranslateAnchor(@Property.ICON_TRANSLATE_ANCHOR String value) {
- return new PaintProperty<>("icon-translate-anchor", value);
+ public static PropertyValue<String> iconTranslateAnchor(@Property.ICON_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("icon-translate-anchor", value);
}
+
/**
* Controls the translation reference point.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconTranslateAnchor(Function<String> function) {
- return new PaintProperty<>("icon-translate-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("icon-translate-anchor", function);
}
/**
@@ -584,18 +620,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textOpacity(Float value) {
- return new PaintProperty<>("text-opacity", value);
+ public static PropertyValue<Float> textOpacity(Float value) {
+ return new PaintPropertyValue<>("text-opacity", value);
}
+
/**
* The opacity at which the text will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textOpacity(Function<Float> function) {
- return new PaintProperty<>("text-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> textOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("text-opacity", function);
}
/**
@@ -604,8 +642,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> textColor(@ColorInt int value) {
- return new PaintProperty<>("text-color", colorToRgbaString(value));
+ public static PropertyValue<String> textColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("text-color", colorToRgbaString(value));
}
/**
@@ -614,18 +652,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textColor(String value) {
- return new PaintProperty<>("text-color", value);
+ public static PropertyValue<String> textColor(String value) {
+ return new PaintPropertyValue<>("text-color", value);
}
+
/**
* The color with which the text will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textColor(Function<String> function) {
- return new PaintProperty<>("text-color", function);
+ public static <T> PropertyValue<Function<T, String>> textColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("text-color", function);
}
/**
@@ -634,8 +674,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> textHaloColor(@ColorInt int value) {
- return new PaintProperty<>("text-halo-color", colorToRgbaString(value));
+ public static PropertyValue<String> textHaloColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("text-halo-color", colorToRgbaString(value));
}
/**
@@ -644,18 +684,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textHaloColor(String value) {
- return new PaintProperty<>("text-halo-color", value);
+ public static PropertyValue<String> textHaloColor(String value) {
+ return new PaintPropertyValue<>("text-halo-color", value);
}
+
/**
* The color of the text's halo, which helps it stand out from backgrounds.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textHaloColor(Function<String> function) {
- return new PaintProperty<>("text-halo-color", function);
+ public static <T> PropertyValue<Function<T, String>> textHaloColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("text-halo-color", function);
}
/**
@@ -664,18 +706,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textHaloWidth(Float value) {
- return new PaintProperty<>("text-halo-width", value);
+ public static PropertyValue<Float> textHaloWidth(Float value) {
+ return new PaintPropertyValue<>("text-halo-width", value);
}
+
/**
* Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textHaloWidth(Function<Float> function) {
- return new PaintProperty<>("text-halo-width", function);
+ public static <T> PropertyValue<Function<T, Float>> textHaloWidth(Function<T, Float> function) {
+ return new PaintPropertyValue<>("text-halo-width", function);
}
/**
@@ -684,40 +728,42 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textHaloBlur(Float value) {
- return new PaintProperty<>("text-halo-blur", value);
+ public static PropertyValue<Float> textHaloBlur(Float value) {
+ return new PaintPropertyValue<>("text-halo-blur", value);
}
+
/**
* The halo's fadeout distance towards the outside.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textHaloBlur(Function<Float> function) {
- return new PaintProperty<>("text-halo-blur", function);
+ public static <T> PropertyValue<Function<T, Float>> textHaloBlur(Function<T, Float> function) {
+ return new PaintPropertyValue<>("text-halo-blur", function);
}
/**
- * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down,
- * while negative values indicate left and up.
+ * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> textTranslate(Float[] value) {
- return new PaintProperty<>("text-translate", value);
+ public static PropertyValue<Float[]> textTranslate(Float[] value) {
+ return new PaintPropertyValue<>("text-translate", value);
}
+
/**
- * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down,
- * while negative values indicate left and up.
+ * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> textTranslate(Function<Float[]> function) {
- return new PaintProperty<>("text-translate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> textTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("text-translate", function);
}
/**
@@ -726,18 +772,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textTranslateAnchor(@Property.TEXT_TRANSLATE_ANCHOR String value) {
- return new PaintProperty<>("text-translate-anchor", value);
+ public static PropertyValue<String> textTranslateAnchor(@Property.TEXT_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("text-translate-anchor", value);
}
+
/**
* Controls the translation reference point.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textTranslateAnchor(Function<String> function) {
- return new PaintProperty<>("text-translate-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("text-translate-anchor", function);
}
/**
@@ -746,18 +794,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> circleRadius(Float value) {
- return new PaintProperty<>("circle-radius", value);
+ public static PropertyValue<Float> circleRadius(Float value) {
+ return new PaintPropertyValue<>("circle-radius", value);
}
+
/**
* Circle radius.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> circleRadius(Function<Float> function) {
- return new PaintProperty<>("circle-radius", function);
+ public static <T> PropertyValue<Function<T, Float>> circleRadius(Function<T, Float> function) {
+ return new PaintPropertyValue<>("circle-radius", function);
}
/**
@@ -766,8 +816,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> circleColor(@ColorInt int value) {
- return new PaintProperty<>("circle-color", colorToRgbaString(value));
+ public static PropertyValue<String> circleColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("circle-color", colorToRgbaString(value));
}
/**
@@ -776,18 +826,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> circleColor(String value) {
- return new PaintProperty<>("circle-color", value);
+ public static PropertyValue<String> circleColor(String value) {
+ return new PaintPropertyValue<>("circle-color", value);
}
+
/**
* The fill color of the circle.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> circleColor(Function<String> function) {
- return new PaintProperty<>("circle-color", function);
+ public static <T> PropertyValue<Function<T, String>> circleColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("circle-color", function);
}
/**
@@ -796,18 +848,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> circleBlur(Float value) {
- return new PaintProperty<>("circle-blur", value);
+ public static PropertyValue<Float> circleBlur(Float value) {
+ return new PaintPropertyValue<>("circle-blur", value);
}
+
/**
* Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> circleBlur(Function<Float> function) {
- return new PaintProperty<>("circle-blur", function);
+ public static <T> PropertyValue<Function<T, Float>> circleBlur(Function<T, Float> function) {
+ return new PaintPropertyValue<>("circle-blur", function);
}
/**
@@ -816,18 +870,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> circleOpacity(Float value) {
- return new PaintProperty<>("circle-opacity", value);
+ public static PropertyValue<Float> circleOpacity(Float value) {
+ return new PaintPropertyValue<>("circle-opacity", value);
}
+
/**
* The opacity at which the circle will be drawn.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> circleOpacity(Function<Float> function) {
- return new PaintProperty<>("circle-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> circleOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("circle-opacity", function);
}
/**
@@ -836,18 +892,20 @@ public class PropertyFactory {
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> circleTranslate(Float[] value) {
- return new PaintProperty<>("circle-translate", value);
+ public static PropertyValue<Float[]> circleTranslate(Float[] value) {
+ return new PaintPropertyValue<>("circle-translate", value);
}
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> circleTranslate(Function<Float[]> function) {
- return new PaintProperty<>("circle-translate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> circleTranslate(CameraFunction<Z, Float[]> function) {
+ return new PaintPropertyValue<>("circle-translate", function);
}
/**
@@ -856,18 +914,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> circleTranslateAnchor(@Property.CIRCLE_TRANSLATE_ANCHOR String value) {
- return new PaintProperty<>("circle-translate-anchor", value);
+ public static PropertyValue<String> circleTranslateAnchor(@Property.CIRCLE_TRANSLATE_ANCHOR String value) {
+ return new PaintPropertyValue<>("circle-translate-anchor", value);
}
+
/**
* Controls the translation reference point.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> circleTranslateAnchor(Function<String> function) {
- return new PaintProperty<>("circle-translate-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circleTranslateAnchor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("circle-translate-anchor", function);
}
/**
@@ -876,38 +936,42 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> circlePitchScale(@Property.CIRCLE_PITCH_SCALE String value) {
- return new PaintProperty<>("circle-pitch-scale", value);
+ public static PropertyValue<String> circlePitchScale(@Property.CIRCLE_PITCH_SCALE String value) {
+ return new PaintPropertyValue<>("circle-pitch-scale", value);
}
+
/**
* Controls the scaling behavior of the circle when the map is pitched.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> circlePitchScale(Function<String> function) {
- return new PaintProperty<>("circle-pitch-scale", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circlePitchScale(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("circle-pitch-scale", function);
}
/**
- * The width of the circle's stroke. Strokes are placed outside of the "circle-radius".
+ * The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}.
*
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> circleStrokeWidth(Float value) {
- return new PaintProperty<>("circle-stroke-width", value);
+ public static PropertyValue<Float> circleStrokeWidth(Float value) {
+ return new PaintPropertyValue<>("circle-stroke-width", value);
}
+
/**
- * The width of the circle's stroke. Strokes are placed outside of the "circle-radius".
+ * The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> circleStrokeWidth(Function<Float> function) {
- return new PaintProperty<>("circle-stroke-width", function);
+ public static <T> PropertyValue<Function<T, Float>> circleStrokeWidth(Function<T, Float> function) {
+ return new PaintPropertyValue<>("circle-stroke-width", function);
}
/**
@@ -916,8 +980,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> circleStrokeColor(@ColorInt int value) {
- return new PaintProperty<>("circle-stroke-color", colorToRgbaString(value));
+ public static PropertyValue<String> circleStrokeColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("circle-stroke-color", colorToRgbaString(value));
}
/**
@@ -926,18 +990,20 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> circleStrokeColor(String value) {
- return new PaintProperty<>("circle-stroke-color", value);
+ public static PropertyValue<String> circleStrokeColor(String value) {
+ return new PaintPropertyValue<>("circle-stroke-color", value);
}
+
/**
* The stroke color of the circle.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> circleStrokeColor(Function<String> function) {
- return new PaintProperty<>("circle-stroke-color", function);
+ public static <T> PropertyValue<Function<T, String>> circleStrokeColor(Function<T, String> function) {
+ return new PaintPropertyValue<>("circle-stroke-color", function);
}
/**
@@ -946,18 +1012,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> circleStrokeOpacity(Float value) {
- return new PaintProperty<>("circle-stroke-opacity", value);
+ public static PropertyValue<Float> circleStrokeOpacity(Float value) {
+ return new PaintPropertyValue<>("circle-stroke-opacity", value);
}
+
/**
* The opacity of the circle's stroke.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> circleStrokeOpacity(Function<Float> function) {
- return new PaintProperty<>("circle-stroke-opacity", function);
+ public static <T> PropertyValue<Function<T, Float>> circleStrokeOpacity(Function<T, Float> function) {
+ return new PaintPropertyValue<>("circle-stroke-opacity", function);
}
/**
@@ -966,18 +1034,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterOpacity(Float value) {
- return new PaintProperty<>("raster-opacity", value);
+ public static PropertyValue<Float> rasterOpacity(Float value) {
+ return new PaintPropertyValue<>("raster-opacity", value);
}
+
/**
* The opacity at which the image will be drawn.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterOpacity(Function<Float> function) {
- return new PaintProperty<>("raster-opacity", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterOpacity(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-opacity", function);
}
/**
@@ -986,18 +1056,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterHueRotate(Float value) {
- return new PaintProperty<>("raster-hue-rotate", value);
+ public static PropertyValue<Float> rasterHueRotate(Float value) {
+ return new PaintPropertyValue<>("raster-hue-rotate", value);
}
+
/**
* Rotates hues around the color wheel.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterHueRotate(Function<Float> function) {
- return new PaintProperty<>("raster-hue-rotate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterHueRotate(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-hue-rotate", function);
}
/**
@@ -1006,18 +1078,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterBrightnessMin(Float value) {
- return new PaintProperty<>("raster-brightness-min", value);
+ public static PropertyValue<Float> rasterBrightnessMin(Float value) {
+ return new PaintPropertyValue<>("raster-brightness-min", value);
}
+
/**
* Increase or reduce the brightness of the image. The value is the minimum brightness.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterBrightnessMin(Function<Float> function) {
- return new PaintProperty<>("raster-brightness-min", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterBrightnessMin(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-brightness-min", function);
}
/**
@@ -1026,18 +1100,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterBrightnessMax(Float value) {
- return new PaintProperty<>("raster-brightness-max", value);
+ public static PropertyValue<Float> rasterBrightnessMax(Float value) {
+ return new PaintPropertyValue<>("raster-brightness-max", value);
}
+
/**
* Increase or reduce the brightness of the image. The value is the maximum brightness.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterBrightnessMax(Function<Float> function) {
- return new PaintProperty<>("raster-brightness-max", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterBrightnessMax(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-brightness-max", function);
}
/**
@@ -1046,18 +1122,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterSaturation(Float value) {
- return new PaintProperty<>("raster-saturation", value);
+ public static PropertyValue<Float> rasterSaturation(Float value) {
+ return new PaintPropertyValue<>("raster-saturation", value);
}
+
/**
* Increase or reduce the saturation of the image.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterSaturation(Function<Float> function) {
- return new PaintProperty<>("raster-saturation", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterSaturation(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-saturation", function);
}
/**
@@ -1066,18 +1144,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterContrast(Float value) {
- return new PaintProperty<>("raster-contrast", value);
+ public static PropertyValue<Float> rasterContrast(Float value) {
+ return new PaintPropertyValue<>("raster-contrast", value);
}
+
/**
* Increase or reduce the contrast of the image.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterContrast(Function<Float> function) {
- return new PaintProperty<>("raster-contrast", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterContrast(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-contrast", function);
}
/**
@@ -1086,18 +1166,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> rasterFadeDuration(Float value) {
- return new PaintProperty<>("raster-fade-duration", value);
+ public static PropertyValue<Float> rasterFadeDuration(Float value) {
+ return new PaintPropertyValue<>("raster-fade-duration", value);
}
+
/**
* Fade duration when a new tile is added.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> rasterFadeDuration(Function<Float> function) {
- return new PaintProperty<>("raster-fade-duration", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterFadeDuration(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("raster-fade-duration", function);
}
/**
@@ -1106,8 +1188,8 @@ public class PropertyFactory {
* @param value a int color value
* @return property wrapper around String color
*/
- public static Property<String> backgroundColor(@ColorInt int value) {
- return new PaintProperty<>("background-color", colorToRgbaString(value));
+ public static PropertyValue<String> backgroundColor(@ColorInt int value) {
+ return new PaintPropertyValue<>("background-color", colorToRgbaString(value));
}
/**
@@ -1116,40 +1198,42 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> backgroundColor(String value) {
- return new PaintProperty<>("background-color", value);
+ public static PropertyValue<String> backgroundColor(String value) {
+ return new PaintPropertyValue<>("background-color", value);
}
+
/**
* The color with which the background will be drawn.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> backgroundColor(Function<String> function) {
- return new PaintProperty<>("background-color", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> backgroundColor(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("background-color", function);
}
/**
- * 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).
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> backgroundPattern(String value) {
- return new PaintProperty<>("background-pattern", value);
+ public static PropertyValue<String> backgroundPattern(String value) {
+ return new PaintPropertyValue<>("background-pattern", value);
}
+
/**
- * 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).
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> backgroundPattern(Function<String> function) {
- return new PaintProperty<>("background-pattern", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> backgroundPattern(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("background-pattern", function);
}
/**
@@ -1158,18 +1242,20 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> backgroundOpacity(Float value) {
- return new PaintProperty<>("background-opacity", value);
+ public static PropertyValue<Float> backgroundOpacity(Float value) {
+ return new PaintPropertyValue<>("background-opacity", value);
}
+
/**
* The opacity at which the background will be drawn.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> backgroundOpacity(Function<Float> function) {
- return new PaintProperty<>("background-opacity", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> backgroundOpacity(CameraFunction<Z, Float> function) {
+ return new PaintPropertyValue<>("background-opacity", function);
}
/**
@@ -1178,18 +1264,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> lineCap(@Property.LINE_CAP String value) {
- return new LayoutProperty<>("line-cap", value);
+ public static PropertyValue<String> lineCap(@Property.LINE_CAP String value) {
+ return new LayoutPropertyValue<>("line-cap", value);
}
+
+
/**
* The display of line endings.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> lineCap(Function<String> function) {
- return new LayoutProperty<>("line-cap", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> lineCap(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("line-cap", function);
}
/**
@@ -1198,18 +1287,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> lineJoin(@Property.LINE_JOIN String value) {
- return new LayoutProperty<>("line-join", value);
+ public static PropertyValue<String> lineJoin(@Property.LINE_JOIN String value) {
+ return new LayoutPropertyValue<>("line-join", value);
}
+
+
/**
* The display of lines when joining.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> lineJoin(Function<String> function) {
- return new LayoutProperty<>("line-join", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> lineJoin(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("line-join", function);
}
/**
@@ -1218,18 +1310,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineMiterLimit(Float value) {
- return new LayoutProperty<>("line-miter-limit", value);
+ public static PropertyValue<Float> lineMiterLimit(Float value) {
+ return new LayoutPropertyValue<>("line-miter-limit", value);
}
+
+
/**
* Used to automatically convert miter joins to bevel joins for sharp angles.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineMiterLimit(Function<Float> function) {
- return new LayoutProperty<>("line-miter-limit", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> lineMiterLimit(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("line-miter-limit", function);
}
/**
@@ -1238,18 +1333,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> lineRoundLimit(Float value) {
- return new LayoutProperty<>("line-round-limit", value);
+ public static PropertyValue<Float> lineRoundLimit(Float value) {
+ return new LayoutPropertyValue<>("line-round-limit", value);
}
+
+
/**
* Used to automatically convert round joins to miter joins for shallow angles.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> lineRoundLimit(Function<Float> function) {
- return new LayoutProperty<>("line-round-limit", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> lineRoundLimit(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("line-round-limit", function);
}
/**
@@ -1258,18 +1356,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> symbolPlacement(@Property.SYMBOL_PLACEMENT String value) {
- return new LayoutProperty<>("symbol-placement", value);
+ public static PropertyValue<String> symbolPlacement(@Property.SYMBOL_PLACEMENT String value) {
+ return new LayoutPropertyValue<>("symbol-placement", value);
}
+
+
/**
* Label placement relative to its geometry.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> symbolPlacement(Function<String> function) {
- return new LayoutProperty<>("symbol-placement", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> symbolPlacement(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("symbol-placement", function);
}
/**
@@ -1278,42 +1379,44 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> symbolSpacing(Float value) {
- return new LayoutProperty<>("symbol-spacing", value);
+ public static PropertyValue<Float> symbolSpacing(Float value) {
+ return new LayoutPropertyValue<>("symbol-spacing", value);
}
+
+
/**
* Distance between two symbol anchors.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> symbolSpacing(Function<Float> function) {
- return new LayoutProperty<>("symbol-spacing", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> symbolSpacing(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("symbol-spacing", function);
}
/**
- * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have
- * enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line
- * symbol layer.
+ * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
*
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> symbolAvoidEdges(Boolean value) {
- return new LayoutProperty<>("symbol-avoid-edges", value);
+ public static PropertyValue<Boolean> symbolAvoidEdges(Boolean value) {
+ return new LayoutPropertyValue<>("symbol-avoid-edges", value);
}
+
+
/**
- * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have
- * enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line
- * symbol layer.
+ * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> symbolAvoidEdges(Function<Boolean> function) {
- return new LayoutProperty<>("symbol-avoid-edges", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> symbolAvoidEdges(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("symbol-avoid-edges", function);
}
/**
@@ -1322,18 +1425,21 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> iconAllowOverlap(Boolean value) {
- return new LayoutProperty<>("icon-allow-overlap", value);
+ public static PropertyValue<Boolean> iconAllowOverlap(Boolean value) {
+ return new LayoutPropertyValue<>("icon-allow-overlap", value);
}
+
+
/**
* If true, the icon will be visible even if it collides with other previously drawn symbols.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> iconAllowOverlap(Function<Boolean> function) {
- return new LayoutProperty<>("icon-allow-overlap", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> iconAllowOverlap(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("icon-allow-overlap", function);
}
/**
@@ -1342,40 +1448,44 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> iconIgnorePlacement(Boolean value) {
- return new LayoutProperty<>("icon-ignore-placement", value);
+ public static PropertyValue<Boolean> iconIgnorePlacement(Boolean value) {
+ return new LayoutPropertyValue<>("icon-ignore-placement", value);
}
+
+
/**
* If true, other symbols can be visible even if they collide with the icon.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> iconIgnorePlacement(Function<Boolean> function) {
- return new LayoutProperty<>("icon-ignore-placement", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> iconIgnorePlacement(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("icon-ignore-placement", function);
}
/**
- * If true, text will display without their corresponding icons when the icon collides with other symbols and the
- * text does not.
+ * If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
*
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> iconOptional(Boolean value) {
- return new LayoutProperty<>("icon-optional", value);
+ public static PropertyValue<Boolean> iconOptional(Boolean value) {
+ return new LayoutPropertyValue<>("icon-optional", value);
}
+
+
/**
- * If true, text will display without their corresponding icons when the icon collides with other symbols and the
- * text does not.
+ * If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> iconOptional(Function<Boolean> function) {
- return new LayoutProperty<>("icon-optional", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> iconOptional(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("icon-optional", function);
}
/**
@@ -1384,18 +1494,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconRotationAlignment(@Property.ICON_ROTATION_ALIGNMENT String value) {
- return new LayoutProperty<>("icon-rotation-alignment", value);
+ public static PropertyValue<String> iconRotationAlignment(@Property.ICON_ROTATION_ALIGNMENT String value) {
+ return new LayoutPropertyValue<>("icon-rotation-alignment", value);
}
+
+
/**
* In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of icons.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconRotationAlignment(Function<String> function) {
- return new LayoutProperty<>("icon-rotation-alignment", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconRotationAlignment(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("icon-rotation-alignment", function);
}
/**
@@ -1404,18 +1517,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconSize(Float value) {
- return new LayoutProperty<>("icon-size", value);
+ public static PropertyValue<Float> iconSize(Float value) {
+ return new LayoutPropertyValue<>("icon-size", value);
}
+
+
/**
* Scale factor for icon. 1 is original size, 3 triples the size.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconSize(Function<Float> function) {
- return new LayoutProperty<>("icon-size", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconSize(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("icon-size", function);
}
/**
@@ -1424,40 +1540,44 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconTextFit(@Property.ICON_TEXT_FIT String value) {
- return new LayoutProperty<>("icon-text-fit", value);
+ public static PropertyValue<String> iconTextFit(@Property.ICON_TEXT_FIT String value) {
+ return new LayoutPropertyValue<>("icon-text-fit", value);
}
+
+
/**
* Scales the icon to fit around the associated text.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconTextFit(Function<String> function) {
- return new LayoutProperty<>("icon-text-fit", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconTextFit(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("icon-text-fit", function);
}
/**
- * Size of the additional area added to dimensions determined by {@link Property.ICON_TEXT_FIT}, in clockwise order:
- * top, right, bottom, left.
+ * Size of the additional area added to dimensions determined by {@link Property.ICON_TEXT_FIT}, in clockwise order: top, right, bottom, left.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> iconTextFitPadding(Float[] value) {
- return new LayoutProperty<>("icon-text-fit-padding", value);
+ public static PropertyValue<Float[]> iconTextFitPadding(Float[] value) {
+ return new LayoutPropertyValue<>("icon-text-fit-padding", value);
}
+
+
/**
- * Size of the additional area added to dimensions determined by {@link Property.ICON_TEXT_FIT}, in clockwise order:
- * top, right, bottom, left.
+ * Size of the additional area added to dimensions determined by {@link Property.ICON_TEXT_FIT}, in clockwise order: top, right, bottom, left.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> iconTextFitPadding(Function<Float[]> function) {
- return new LayoutProperty<>("icon-text-fit-padding", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> iconTextFitPadding(CameraFunction<Z, Float[]> function) {
+ return new LayoutPropertyValue<>("icon-text-fit-padding", function);
}
/**
@@ -1466,18 +1586,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> iconImage(String value) {
- return new LayoutProperty<>("icon-image", value);
+ public static PropertyValue<String> iconImage(String value) {
+ return new LayoutPropertyValue<>("icon-image", value);
}
+
+
/**
* A string with {tokens} replaced, referencing the data property to pull from.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> iconImage(Function<String> function) {
- return new LayoutProperty<>("icon-image", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconImage(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("icon-image", function);
}
/**
@@ -1486,18 +1609,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconRotate(Float value) {
- return new LayoutProperty<>("icon-rotate", value);
+ public static PropertyValue<Float> iconRotate(Float value) {
+ return new LayoutPropertyValue<>("icon-rotate", value);
}
+
+
/**
* Rotates the icon clockwise.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconRotate(Function<Float> function) {
- return new LayoutProperty<>("icon-rotate", function);
+ public static <T> PropertyValue<Function<T, Float>> iconRotate(Function<T, Float> function) {
+ return new LayoutPropertyValue<>("icon-rotate", function);
}
/**
@@ -1506,18 +1632,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> iconPadding(Float value) {
- return new LayoutProperty<>("icon-padding", value);
+ public static PropertyValue<Float> iconPadding(Float value) {
+ return new LayoutPropertyValue<>("icon-padding", value);
}
+
+
/**
* Size of the additional area around the icon bounding box used for detecting symbol collisions.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> iconPadding(Function<Float> function) {
- return new LayoutProperty<>("icon-padding", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> iconPadding(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("icon-padding", function);
}
/**
@@ -1526,40 +1655,44 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> iconKeepUpright(Boolean value) {
- return new LayoutProperty<>("icon-keep-upright", value);
+ public static PropertyValue<Boolean> iconKeepUpright(Boolean value) {
+ return new LayoutPropertyValue<>("icon-keep-upright", value);
}
+
+
/**
* If true, the icon may be flipped to prevent it from being rendered upside-down.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> iconKeepUpright(Function<Boolean> function) {
- return new LayoutProperty<>("icon-keep-upright", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> iconKeepUpright(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("icon-keep-upright", function);
}
/**
- * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate
- * left and up.
+ * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up. When combined with {@link PropertyFactory#iconRotate} the offset will be as if the rotated direction was up.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> iconOffset(Float[] value) {
- return new LayoutProperty<>("icon-offset", value);
+ public static PropertyValue<Float[]> iconOffset(Float[] value) {
+ return new LayoutPropertyValue<>("icon-offset", value);
}
+
+
/**
- * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate
- * left and up.
+ * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up. When combined with {@link PropertyFactory#iconRotate} the offset will be as if the rotated direction was up.
*
+ * @param <T> the function input type
* @param function a wrapper function for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> iconOffset(Function<Float[]> function) {
- return new LayoutProperty<>("icon-offset", function);
+ public static <T> PropertyValue<Function<T, Float[]>> iconOffset(Function<T, Float[]> function) {
+ return new LayoutPropertyValue<>("icon-offset", function);
}
/**
@@ -1568,60 +1701,67 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textPitchAlignment(@Property.TEXT_PITCH_ALIGNMENT String value) {
- return new LayoutProperty<>("text-pitch-alignment", value);
+ public static PropertyValue<String> textPitchAlignment(@Property.TEXT_PITCH_ALIGNMENT String value) {
+ return new LayoutPropertyValue<>("text-pitch-alignment", value);
}
+
+
/**
* Orientation of text when map is pitched.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textPitchAlignment(Function<String> function) {
- return new LayoutProperty<>("text-pitch-alignment", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textPitchAlignment(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("text-pitch-alignment", function);
}
/**
- * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of the individual glyphs
- * forming the text.
+ * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of the individual glyphs forming the text.
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textRotationAlignment(@Property.TEXT_ROTATION_ALIGNMENT String value) {
- return new LayoutProperty<>("text-rotation-alignment", value);
+ public static PropertyValue<String> textRotationAlignment(@Property.TEXT_ROTATION_ALIGNMENT String value) {
+ return new LayoutPropertyValue<>("text-rotation-alignment", value);
}
+
+
/**
- * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of the individual glyphs
- * forming the text.
+ * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of the individual glyphs forming the text.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textRotationAlignment(Function<String> function) {
- return new LayoutProperty<>("text-rotation-alignment", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textRotationAlignment(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("text-rotation-alignment", function);
}
/**
- * Value to use for a text label. Feature properties are specified using tokens like {field_name}.
+ * Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
*
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textField(String value) {
- return new LayoutProperty<>("text-field", value);
+ public static PropertyValue<String> textField(String value) {
+ return new LayoutPropertyValue<>("text-field", value);
}
+
+
/**
- * Value to use for a text label. Feature properties are specified using tokens like {field_name}.
+ * Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textField(Function<String> function) {
- return new LayoutProperty<>("text-field", function);
+ public static <T> PropertyValue<Function<T, String>> textField(Function<T, String> function) {
+ return new LayoutPropertyValue<>("text-field", function);
}
/**
@@ -1630,18 +1770,21 @@ public class PropertyFactory {
* @param value a String[] value
* @return property wrapper around String[]
*/
- public static Property<String[]> textFont(String[] value) {
- return new LayoutProperty<>("text-font", value);
+ public static PropertyValue<String[]> textFont(String[] value) {
+ return new LayoutPropertyValue<>("text-font", value);
}
+
+
/**
* Font stack to use for displaying text.
*
- * @param function a wrapper function for String[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String[]
* @return property wrapper around a String[] function
*/
- public static Property<Function<String[]>> textFont(Function<String[]> function) {
- return new LayoutProperty<>("text-font", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String[]>> textFont(CameraFunction<Z, String[]> function) {
+ return new LayoutPropertyValue<>("text-font", function);
}
/**
@@ -1650,18 +1793,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textSize(Float value) {
- return new LayoutProperty<>("text-size", value);
+ public static PropertyValue<Float> textSize(Float value) {
+ return new LayoutPropertyValue<>("text-size", value);
}
+
+
/**
* Font size.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textSize(Function<Float> function) {
- return new LayoutProperty<>("text-size", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textSize(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-size", function);
}
/**
@@ -1670,18 +1816,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textMaxWidth(Float value) {
- return new LayoutProperty<>("text-max-width", value);
+ public static PropertyValue<Float> textMaxWidth(Float value) {
+ return new LayoutPropertyValue<>("text-max-width", value);
}
+
+
/**
* The maximum line width for text wrapping.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textMaxWidth(Function<Float> function) {
- return new LayoutProperty<>("text-max-width", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textMaxWidth(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-max-width", function);
}
/**
@@ -1690,18 +1839,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textLineHeight(Float value) {
- return new LayoutProperty<>("text-line-height", value);
+ public static PropertyValue<Float> textLineHeight(Float value) {
+ return new LayoutPropertyValue<>("text-line-height", value);
}
+
+
/**
* Text leading value for multi-line text.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textLineHeight(Function<Float> function) {
- return new LayoutProperty<>("text-line-height", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textLineHeight(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-line-height", function);
}
/**
@@ -1710,18 +1862,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textLetterSpacing(Float value) {
- return new LayoutProperty<>("text-letter-spacing", value);
+ public static PropertyValue<Float> textLetterSpacing(Float value) {
+ return new LayoutPropertyValue<>("text-letter-spacing", value);
}
+
+
/**
* Text tracking amount.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textLetterSpacing(Function<Float> function) {
- return new LayoutProperty<>("text-letter-spacing", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textLetterSpacing(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-letter-spacing", function);
}
/**
@@ -1730,18 +1885,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textJustify(@Property.TEXT_JUSTIFY String value) {
- return new LayoutProperty<>("text-justify", value);
+ public static PropertyValue<String> textJustify(@Property.TEXT_JUSTIFY String value) {
+ return new LayoutPropertyValue<>("text-justify", value);
}
+
+
/**
* Text justification options.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textJustify(Function<String> function) {
- return new LayoutProperty<>("text-justify", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textJustify(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("text-justify", function);
}
/**
@@ -1750,18 +1908,21 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textAnchor(@Property.TEXT_ANCHOR String value) {
- return new LayoutProperty<>("text-anchor", value);
+ public static PropertyValue<String> textAnchor(@Property.TEXT_ANCHOR String value) {
+ return new LayoutPropertyValue<>("text-anchor", value);
}
+
+
/**
* Part of the text placed closest to the anchor.
*
- * @param function a wrapper function for String
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textAnchor(Function<String> function) {
- return new LayoutProperty<>("text-anchor", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textAnchor(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("text-anchor", function);
}
/**
@@ -1770,18 +1931,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textMaxAngle(Float value) {
- return new LayoutProperty<>("text-max-angle", value);
+ public static PropertyValue<Float> textMaxAngle(Float value) {
+ return new LayoutPropertyValue<>("text-max-angle", value);
}
+
+
/**
* Maximum angle change between adjacent characters.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textMaxAngle(Function<Float> function) {
- return new LayoutProperty<>("text-max-angle", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textMaxAngle(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-max-angle", function);
}
/**
@@ -1790,18 +1954,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textRotate(Float value) {
- return new LayoutProperty<>("text-rotate", value);
+ public static PropertyValue<Float> textRotate(Float value) {
+ return new LayoutPropertyValue<>("text-rotate", value);
}
+
+
/**
* Rotates the text clockwise.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textRotate(Function<Float> function) {
- return new LayoutProperty<>("text-rotate", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textRotate(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-rotate", function);
}
/**
@@ -1810,18 +1977,21 @@ public class PropertyFactory {
* @param value a Float value
* @return property wrapper around Float
*/
- public static Property<Float> textPadding(Float value) {
- return new LayoutProperty<>("text-padding", value);
+ public static PropertyValue<Float> textPadding(Float value) {
+ return new LayoutPropertyValue<>("text-padding", value);
}
+
+
/**
* Size of the additional area around the text bounding box used for detecting symbol collisions.
*
- * @param function a wrapper function for Float
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
- public static Property<Function<Float>> textPadding(Function<Float> function) {
- return new LayoutProperty<>("text-padding", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textPadding(CameraFunction<Z, Float> function) {
+ return new LayoutPropertyValue<>("text-padding", function);
}
/**
@@ -1830,18 +2000,21 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> textKeepUpright(Boolean value) {
- return new LayoutProperty<>("text-keep-upright", value);
+ public static PropertyValue<Boolean> textKeepUpright(Boolean value) {
+ return new LayoutPropertyValue<>("text-keep-upright", value);
}
+
+
/**
* If true, the text may be flipped vertically to prevent it from being rendered upside-down.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> textKeepUpright(Function<Boolean> function) {
- return new LayoutProperty<>("text-keep-upright", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> textKeepUpright(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("text-keep-upright", function);
}
/**
@@ -1850,40 +2023,44 @@ public class PropertyFactory {
* @param value a String value
* @return property wrapper around String
*/
- public static Property<String> textTransform(@Property.TEXT_TRANSFORM String value) {
- return new LayoutProperty<>("text-transform", value);
+ public static PropertyValue<String> textTransform(@Property.TEXT_TRANSFORM String value) {
+ return new LayoutPropertyValue<>("text-transform", value);
}
+
+
/**
* Specifies how to capitalize text, similar to the CSS {@link PropertyFactory#textTransform} property.
*
+ * @param <T> the function input type
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static Property<Function<String>> textTransform(Function<String> function) {
- return new LayoutProperty<>("text-transform", function);
+ public static <T> PropertyValue<Function<T, String>> textTransform(Function<T, String> function) {
+ return new LayoutPropertyValue<>("text-transform", function);
}
/**
- * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate
- * left and up.
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
*
* @param value a Float[] value
* @return property wrapper around Float[]
*/
- public static Property<Float[]> textOffset(Float[] value) {
- return new LayoutProperty<>("text-offset", value);
+ public static PropertyValue<Float[]> textOffset(Float[] value) {
+ return new LayoutPropertyValue<>("text-offset", value);
}
+
+
/**
- * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate
- * left and up.
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
*
- * @param function a wrapper function for Float[]
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
- public static Property<Function<Float[]>> textOffset(Function<Float[]> function) {
- return new LayoutProperty<>("text-offset", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> textOffset(CameraFunction<Z, Float[]> function) {
+ return new LayoutPropertyValue<>("text-offset", function);
}
/**
@@ -1892,18 +2069,21 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> textAllowOverlap(Boolean value) {
- return new LayoutProperty<>("text-allow-overlap", value);
+ public static PropertyValue<Boolean> textAllowOverlap(Boolean value) {
+ return new LayoutPropertyValue<>("text-allow-overlap", value);
}
+
+
/**
* If true, the text will be visible even if it collides with other previously drawn symbols.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> textAllowOverlap(Function<Boolean> function) {
- return new LayoutProperty<>("text-allow-overlap", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> textAllowOverlap(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("text-allow-overlap", function);
}
/**
@@ -1912,46 +2092,49 @@ public class PropertyFactory {
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> textIgnorePlacement(Boolean value) {
- return new LayoutProperty<>("text-ignore-placement", value);
+ public static PropertyValue<Boolean> textIgnorePlacement(Boolean value) {
+ return new LayoutPropertyValue<>("text-ignore-placement", value);
}
+
+
/**
* If true, other symbols can be visible even if they collide with the text.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> textIgnorePlacement(Function<Boolean> function) {
- return new LayoutProperty<>("text-ignore-placement", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> textIgnorePlacement(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("text-ignore-placement", function);
}
/**
- * If true, icons will display without their corresponding text when the text collides with other symbols and the
- * icon does not.
+ * If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
*
* @param value a Boolean value
* @return property wrapper around Boolean
*/
- public static Property<Boolean> textOptional(Boolean value) {
- return new LayoutProperty<>("text-optional", value);
+ public static PropertyValue<Boolean> textOptional(Boolean value) {
+ return new LayoutPropertyValue<>("text-optional", value);
}
+
+
/**
- * If true, icons will display without their corresponding text when the text collides with other symbols and the
- * icon does not.
+ * If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
*
- * @param function a wrapper function for Boolean
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
- public static Property<Function<Boolean>> textOptional(Function<Boolean> function) {
- return new LayoutProperty<>("text-optional", function);
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> textOptional(CameraFunction<Z, Boolean> function) {
+ return new LayoutPropertyValue<>("text-optional", function);
}
@SuppressLint("DefaultLocale")
- static String colorToRgbaString(@ColorInt int value) {
- return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF,
- (value >> 24) & 0xFF);
+ public static String colorToRgbaString(@ColorInt int value) {
+ return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
index c404f07c76..5286e6916d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
@@ -1,7 +1,10 @@
package com.mapbox.mapboxsdk.style.layers;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.style.functions.Function;
+
import timber.log.Timber;
/**
@@ -9,9 +12,11 @@ import timber.log.Timber;
*/
public class PropertyValue<T> {
- private final Object value;
+ public final String name;
+ public final T value;
- /* package */ PropertyValue(Object value) {
+ /* package */ PropertyValue(@NonNull String name, T value) {
+ this.name = name;
this.value = value;
}
@@ -28,10 +33,10 @@ public class PropertyValue<T> {
}
@Nullable
- public Function<T> getFunction() {
+ public Function<?, T> getFunction() {
if (isFunction()) {
- //noinspection unchecked
- return (Function<T>) value;
+ // noinspection unchecked
+ return (Function<?, T>) value;
} else {
Timber.w("not a function, try value");
return null;
@@ -41,7 +46,7 @@ public class PropertyValue<T> {
@Nullable
public T getValue() {
if (isValue()) {
- //noinspection unchecked
+ // noinspection unchecked
return (T) value;
} else {
Timber.w("not a value, try function");
@@ -51,7 +56,6 @@ public class PropertyValue<T> {
@Override
public String toString() {
- return String.format("%s (%s)", getClass().getSimpleName(), value != null
- ? value.getClass().getSimpleName() : null);
+ return String.format("%s: %s", name, value);
}
}
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 785106c394..1871686429 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
@@ -1,9 +1,13 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
+import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
+
/**
* Raster map textures such as satellite imagery.
*
@@ -59,7 +63,7 @@ public class RasterLayer extends Layer {
* @param properties the var-args properties
* @return This
*/
- public RasterLayer withProperties(@NonNull Property<?>... properties) {
+ public RasterLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -73,7 +77,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterOpacity());
+ return (PropertyValue<Float>) new PropertyValue("raster-opacity", nativeGetRasterOpacity());
}
/**
@@ -83,7 +87,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterHueRotate() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterHueRotate());
+ return (PropertyValue<Float>) new PropertyValue("raster-hue-rotate", nativeGetRasterHueRotate());
}
/**
@@ -93,7 +97,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterBrightnessMin() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterBrightnessMin());
+ return (PropertyValue<Float>) new PropertyValue("raster-brightness-min", nativeGetRasterBrightnessMin());
}
/**
@@ -103,7 +107,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterBrightnessMax() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterBrightnessMax());
+ return (PropertyValue<Float>) new PropertyValue("raster-brightness-max", nativeGetRasterBrightnessMax());
}
/**
@@ -113,7 +117,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterSaturation() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterSaturation());
+ return (PropertyValue<Float>) new PropertyValue("raster-saturation", nativeGetRasterSaturation());
}
/**
@@ -123,7 +127,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterContrast() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterContrast());
+ return (PropertyValue<Float>) new PropertyValue("raster-contrast", nativeGetRasterContrast());
}
/**
@@ -133,7 +137,7 @@ public class RasterLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getRasterFadeDuration() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetRasterFadeDuration());
+ return (PropertyValue<Float>) new PropertyValue("raster-fade-duration", nativeGetRasterFadeDuration());
}
private native Object nativeGetRasterOpacity();
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 abc516d6d0..c1efdc9636 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
@@ -1,6 +1,7 @@
-package com.mapbox.mapboxsdk.style.layers;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.style.layers;
+
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
@@ -62,27 +63,7 @@ public class SymbolLayer extends Layer {
* @param filter the filter to set
*/
public void setFilter(Filter.Statement filter) {
- this.setFilter(filter.toArray());
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter the filter array to set
- */
- public void setFilter(Object[] filter) {
- nativeSetFilter(filter);
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter tthe filter array to set
- * @return This
- */
- public SymbolLayer withFilter(Object[] filter) {
- setFilter(filter);
- return this;
+ nativeSetFilter(filter.toArray());
}
/**
@@ -96,14 +77,13 @@ public class SymbolLayer extends Layer {
return this;
}
-
/**
* Set a property or properties.
*
* @param properties the var-args properties
* @return This
*/
- public SymbolLayer withProperties(@NonNull Property<?>... properties) {
+ public SymbolLayer withProperties(@NonNull PropertyValue<?>... properties) {
setProperties(properties);
return this;
}
@@ -117,7 +97,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getSymbolPlacement() {
- return (PropertyValue<String>) new PropertyValue(nativeGetSymbolPlacement());
+ return (PropertyValue<String>) new PropertyValue("symbol-placement", nativeGetSymbolPlacement());
}
/**
@@ -127,7 +107,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getSymbolSpacing() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetSymbolSpacing());
+ return (PropertyValue<Float>) new PropertyValue("symbol-spacing", nativeGetSymbolSpacing());
}
/**
@@ -137,7 +117,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getSymbolAvoidEdges() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetSymbolAvoidEdges());
+ return (PropertyValue<Boolean>) new PropertyValue("symbol-avoid-edges", nativeGetSymbolAvoidEdges());
}
/**
@@ -147,7 +127,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconAllowOverlap() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconAllowOverlap());
+ return (PropertyValue<Boolean>) new PropertyValue("icon-allow-overlap", nativeGetIconAllowOverlap());
}
/**
@@ -157,7 +137,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconIgnorePlacement() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconIgnorePlacement());
+ return (PropertyValue<Boolean>) new PropertyValue("icon-ignore-placement", nativeGetIconIgnorePlacement());
}
/**
@@ -167,7 +147,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconOptional() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconOptional());
+ return (PropertyValue<Boolean>) new PropertyValue("icon-optional", nativeGetIconOptional());
}
/**
@@ -177,7 +157,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconRotationAlignment() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconRotationAlignment());
+ return (PropertyValue<String>) new PropertyValue("icon-rotation-alignment", nativeGetIconRotationAlignment());
}
/**
@@ -187,7 +167,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconSize() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconSize());
+ return (PropertyValue<Float>) new PropertyValue("icon-size", nativeGetIconSize());
}
/**
@@ -197,7 +177,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconTextFit() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconTextFit());
+ return (PropertyValue<String>) new PropertyValue("icon-text-fit", nativeGetIconTextFit());
}
/**
@@ -207,7 +187,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconTextFitPadding() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconTextFitPadding());
+ return (PropertyValue<Float[]>) new PropertyValue("icon-text-fit-padding", nativeGetIconTextFitPadding());
}
/**
@@ -217,7 +197,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconImage() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconImage());
+ return (PropertyValue<String>) new PropertyValue("icon-image", nativeGetIconImage());
}
/**
@@ -227,7 +207,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconRotate() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconRotate());
+ return (PropertyValue<Float>) new PropertyValue("icon-rotate", nativeGetIconRotate());
}
/**
@@ -237,7 +217,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconPadding() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconPadding());
+ return (PropertyValue<Float>) new PropertyValue("icon-padding", nativeGetIconPadding());
}
/**
@@ -247,7 +227,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getIconKeepUpright() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetIconKeepUpright());
+ return (PropertyValue<Boolean>) new PropertyValue("icon-keep-upright", nativeGetIconKeepUpright());
}
/**
@@ -257,7 +237,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconOffset() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconOffset());
+ return (PropertyValue<Float[]>) new PropertyValue("icon-offset", nativeGetIconOffset());
}
/**
@@ -267,7 +247,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextPitchAlignment() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextPitchAlignment());
+ return (PropertyValue<String>) new PropertyValue("text-pitch-alignment", nativeGetTextPitchAlignment());
}
/**
@@ -277,7 +257,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextRotationAlignment() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextRotationAlignment());
+ return (PropertyValue<String>) new PropertyValue("text-rotation-alignment", nativeGetTextRotationAlignment());
}
/**
@@ -287,7 +267,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextField() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextField());
+ return (PropertyValue<String>) new PropertyValue("text-field", nativeGetTextField());
}
/**
@@ -297,7 +277,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String[]> getTextFont() {
- return (PropertyValue<String[]>) new PropertyValue(nativeGetTextFont());
+ return (PropertyValue<String[]>) new PropertyValue("text-font", nativeGetTextFont());
}
/**
@@ -307,7 +287,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextSize() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextSize());
+ return (PropertyValue<Float>) new PropertyValue("text-size", nativeGetTextSize());
}
/**
@@ -317,7 +297,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextMaxWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextMaxWidth());
+ return (PropertyValue<Float>) new PropertyValue("text-max-width", nativeGetTextMaxWidth());
}
/**
@@ -327,7 +307,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextLineHeight() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextLineHeight());
+ return (PropertyValue<Float>) new PropertyValue("text-line-height", nativeGetTextLineHeight());
}
/**
@@ -337,7 +317,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextLetterSpacing() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextLetterSpacing());
+ return (PropertyValue<Float>) new PropertyValue("text-letter-spacing", nativeGetTextLetterSpacing());
}
/**
@@ -347,7 +327,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextJustify() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextJustify());
+ return (PropertyValue<String>) new PropertyValue("text-justify", nativeGetTextJustify());
}
/**
@@ -357,7 +337,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextAnchor());
+ return (PropertyValue<String>) new PropertyValue("text-anchor", nativeGetTextAnchor());
}
/**
@@ -367,7 +347,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextMaxAngle() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextMaxAngle());
+ return (PropertyValue<Float>) new PropertyValue("text-max-angle", nativeGetTextMaxAngle());
}
/**
@@ -377,7 +357,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextRotate() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextRotate());
+ return (PropertyValue<Float>) new PropertyValue("text-rotate", nativeGetTextRotate());
}
/**
@@ -387,7 +367,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextPadding() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextPadding());
+ return (PropertyValue<Float>) new PropertyValue("text-padding", nativeGetTextPadding());
}
/**
@@ -397,7 +377,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextKeepUpright() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextKeepUpright());
+ return (PropertyValue<Boolean>) new PropertyValue("text-keep-upright", nativeGetTextKeepUpright());
}
/**
@@ -407,7 +387,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextTransform() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextTransform());
+ return (PropertyValue<String>) new PropertyValue("text-transform", nativeGetTextTransform());
}
/**
@@ -417,7 +397,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getTextOffset() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetTextOffset());
+ return (PropertyValue<Float[]>) new PropertyValue("text-offset", nativeGetTextOffset());
}
/**
@@ -427,7 +407,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextAllowOverlap() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextAllowOverlap());
+ return (PropertyValue<Boolean>) new PropertyValue("text-allow-overlap", nativeGetTextAllowOverlap());
}
/**
@@ -437,7 +417,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextIgnorePlacement() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextIgnorePlacement());
+ return (PropertyValue<Boolean>) new PropertyValue("text-ignore-placement", nativeGetTextIgnorePlacement());
}
/**
@@ -447,7 +427,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Boolean> getTextOptional() {
- return (PropertyValue<Boolean>) new PropertyValue(nativeGetTextOptional());
+ return (PropertyValue<Boolean>) new PropertyValue("text-optional", nativeGetTextOptional());
}
/**
@@ -457,7 +437,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconOpacity());
+ return (PropertyValue<Float>) new PropertyValue("icon-opacity", nativeGetIconOpacity());
}
/**
@@ -467,7 +447,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconColor());
+ return (PropertyValue<String>) new PropertyValue("icon-color", nativeGetIconColor());
}
/**
@@ -494,7 +474,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconHaloColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconHaloColor());
+ return (PropertyValue<String>) new PropertyValue("icon-halo-color", nativeGetIconHaloColor());
}
/**
@@ -521,7 +501,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconHaloWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconHaloWidth());
+ return (PropertyValue<Float>) new PropertyValue("icon-halo-width", nativeGetIconHaloWidth());
}
/**
@@ -531,7 +511,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getIconHaloBlur() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetIconHaloBlur());
+ return (PropertyValue<Float>) new PropertyValue("icon-halo-blur", nativeGetIconHaloBlur());
}
/**
@@ -541,7 +521,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getIconTranslate() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetIconTranslate());
+ return (PropertyValue<Float[]>) new PropertyValue("icon-translate", nativeGetIconTranslate());
}
/**
@@ -551,7 +531,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getIconTranslateAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetIconTranslateAnchor());
+ return (PropertyValue<String>) new PropertyValue("icon-translate-anchor", nativeGetIconTranslateAnchor());
}
/**
@@ -561,7 +541,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextOpacity() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextOpacity());
+ return (PropertyValue<Float>) new PropertyValue("text-opacity", nativeGetTextOpacity());
}
/**
@@ -571,7 +551,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextColor());
+ return (PropertyValue<String>) new PropertyValue("text-color", nativeGetTextColor());
}
/**
@@ -598,7 +578,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextHaloColor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextHaloColor());
+ return (PropertyValue<String>) new PropertyValue("text-halo-color", nativeGetTextHaloColor());
}
/**
@@ -625,7 +605,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextHaloWidth() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextHaloWidth());
+ return (PropertyValue<Float>) new PropertyValue("text-halo-width", nativeGetTextHaloWidth());
}
/**
@@ -635,7 +615,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float> getTextHaloBlur() {
- return (PropertyValue<Float>) new PropertyValue(nativeGetTextHaloBlur());
+ return (PropertyValue<Float>) new PropertyValue("text-halo-blur", nativeGetTextHaloBlur());
}
/**
@@ -645,7 +625,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<Float[]> getTextTranslate() {
- return (PropertyValue<Float[]>) new PropertyValue(nativeGetTextTranslate());
+ return (PropertyValue<Float[]>) new PropertyValue("text-translate", nativeGetTextTranslate());
}
/**
@@ -655,7 +635,7 @@ public class SymbolLayer extends Layer {
*/
@SuppressWarnings("unchecked")
public PropertyValue<String> getTextTranslateAnchor() {
- return (PropertyValue<String>) new PropertyValue(nativeGetTextTranslateAnchor());
+ return (PropertyValue<String>) new PropertyValue("text-translate-anchor", nativeGetTextTranslateAnchor());
}
private native Object nativeGetSymbolPlacement();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/UnknownLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/UnknownLayer.java
new file mode 100644
index 0000000000..4abafcdbeb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/UnknownLayer.java
@@ -0,0 +1,25 @@
+package com.mapbox.mapboxsdk.style.layers;
+
+import android.support.annotation.UiThread;
+
+/**
+ * An unknown type of layer
+ */
+@UiThread
+public class UnknownLayer extends Layer {
+
+ /**
+ * Creates a UnknownLayer.
+ *
+ * @param nativePtr pointer used by core
+ */
+ UnknownLayer(long nativePtr) {
+ super(nativePtr);
+ }
+
+ protected native void initialize();
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
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 4657037df8..5eab4c355e 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
@@ -4,14 +4,14 @@
const doc = locals.doc;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
-package com.mapbox.mapboxsdk.style.layers;
-import android.support.annotation.UiThread;
+package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
-import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
+import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
/**
* <%- doc %>
@@ -21,151 +21,133 @@ import static com.mapbox.mapboxsdk.utils.ColorUtils.*;
@UiThread
public class <%- camelize(type) %>Layer extends Layer {
- /**
- * Creates a <%- camelize(type) %>Layer.
- *
- * @param nativePtr pointer used by core
- */
- public <%- camelize(type) %>Layer(long nativePtr) {
- super(nativePtr);
- }
+ /**
+ * Creates a <%- camelize(type) %>Layer.
+ *
+ * @param nativePtr pointer used by core
+ */
+ public <%- camelize(type) %>Layer(long nativePtr) {
+ super(nativePtr);
+ }
<% if (type === 'background') { -%>
- /**
- * Creates a <%- camelize(type) %>Layer.
- *
- * @param layerId the id of the layer
- */
- public <%- camelize(type) %>Layer(String layerId) {
- initialize(layerId);
- }
+ /**
+ * Creates a <%- camelize(type) %>Layer.
+ *
+ * @param layerId the id of the layer
+ */
+ public <%- camelize(type) %>Layer(String layerId) {
+ initialize(layerId);
+ }
- protected native void initialize(String layerId);
-<% } else { -%>
- /**
- * Creates a <%- camelize(type) %>Layer.
- *
- * @param layerId the id of the layer
- * @param sourceId the id of the source
- */
- public <%- camelize(type) %>Layer(String layerId, String sourceId) {
- initialize(layerId, sourceId);
- }
-
- protected native void initialize(String layerId, String sourceId);
+ protected native void initialize(String layerId);
- /**
- * Set the source layer.
- *
- * @param sourceLayer the source layer to set
- */
- public void setSourceLayer(String sourceLayer) {
- nativeSetSourceLayer(sourceLayer);
- }
+<% } else { -%>
+ /**
+ * Creates a <%- camelize(type) %>Layer.
+ *
+ * @param layerId the id of the layer
+ * @param sourceId the id of the source
+ */
+ public <%- camelize(type) %>Layer(String layerId, String sourceId) {
+ initialize(layerId, sourceId);
+ }
+
+ protected native void initialize(String layerId, String sourceId);
+
+ /**
+ * Set the source layer.
+ *
+ * @param sourceLayer the source layer to set
+ */
+ public void setSourceLayer(String sourceLayer) {
+ nativeSetSourceLayer(sourceLayer);
+ }
+
+ /**
+ * Set the source Layer.
+ *
+ * @param sourceLayer the source layer to set
+ * @return This
+ */
+ public <%- camelize(type) %>Layer withSourceLayer(String sourceLayer) {
+ setSourceLayer(sourceLayer);
+ return this;
+ }
- /**
- * Set the source Layer.
- *
- * @param sourceLayer the source layer to set
- * @return This
- */
- public <%- camelize(type) %>Layer withSourceLayer(String sourceLayer) {
- setSourceLayer(sourceLayer);
- return this;
- }
<% } -%>
<% if (type !== 'background' && type !== 'raster') { -%>
- /**
- * Set a single filter.
- *
- * @param filter the filter to set
- */
- public void setFilter(Filter.Statement filter) {
- this.setFilter(filter.toArray());
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter the filter array to set
- */
- public void setFilter(Object[] filter) {
- nativeSetFilter(filter);
- }
-
- /**
- * Set an array of filters.
- *
- * @param filter tthe filter array to set
- * @return This
- */
- public <%- camelize(type) %>Layer withFilter(Object[] filter) {
- setFilter(filter);
- return this;
- }
-
- /**
- * Set a single filter.
- *
- * @param filter the filter to set
- * @return This
- */
- public <%- camelize(type) %>Layer withFilter(Filter.Statement filter) {
- setFilter(filter);
- return this;
- }
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ */
+ public void setFilter(Filter.Statement filter) {
+ nativeSetFilter(filter.toArray());
+ }
+
+ /**
+ * Set a single filter.
+ *
+ * @param filter the filter to set
+ * @return This
+ */
+ public <%- camelize(type) %>Layer withFilter(Filter.Statement filter) {
+ setFilter(filter);
+ return this;
+ }
<% } -%>
-
- /**
- * Set a property or properties.
- *
- * @param properties the var-args properties
- * @return This
- */
- public <%- camelize(type) %>Layer withProperties(@NonNull Property<?>... properties) {
- setProperties(properties);
- return this;
- }
-
- // Property getters
+ /**
+ * Set a property or properties.
+ *
+ * @param properties the var-args properties
+ * @return This
+ */
+ public <%- camelize(type) %>Layer withProperties(@NonNull PropertyValue<?>... properties) {
+ setProperties(properties);
+ return this;
+ }
+
+ // Property getters
<% for (const property of properties) { -%>
- /**
- * Get the <%- camelize(property.name) %> property
- *
- * @return property wrapper value around <%- propertyType(property) %>
- */
- @SuppressWarnings("unchecked")
- public PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() {
- return (PropertyValue<<%- propertyType(property) %>>) new PropertyValue(nativeGet<%- camelize(property.name) %>());
- }
- <% if (property.type == 'color') { -%>
- /**
- * <%- property.doc %>
- *
- * @return int representation of a rgba string color
- * @throws RuntimeException thrown if property isn't a value
- */
- @ColorInt
- public int get<%- camelize(property.name) %>AsInt() {
- PropertyValue<<%- propertyType(property) %>> value = get<%- camelize(property.name) %>();
- if (value.isValue()) {
- return rgbaToColor(value.getValue());
- } else {
- throw new RuntimeException("<%- property.name %> was set as a Function");
- }
+ /**
+ * Get the <%- camelize(property.name) %> property
+ *
+ * @return property wrapper value around <%- propertyType(property) %>
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<<%- propertyType(property) %>> get<%- camelize(property.name) %>() {
+ return (PropertyValue<<%- propertyType(property) %>>) new PropertyValue("<%- property.name %>", nativeGet<%- camelize(property.name) %>());
+ }
+<% if (property.type == 'color') { -%>
+
+ /**
+ * <%- property.doc %>
+ *
+ * @return int representation of a rgba string color
+ * @throws RuntimeException thrown if property isn't a value
+ */
+ @ColorInt
+ public int get<%- camelize(property.name) %>AsInt() {
+ PropertyValue<<%- propertyType(property) %>> value = get<%- camelize(property.name) %>();
+ if (value.isValue()) {
+ return rgbaToColor(value.getValue());
+ } else {
+ throw new RuntimeException("<%- property.name %> was set as a Function");
}
+ }
- <% } -%>
+<% } -%>
<% } -%>
<% for (const property of properties) { -%>
- private native Object nativeGet<%- camelize(property.name) %>();
+ private native Object nativeGet<%- camelize(property.name) %>();
<% } -%>
- @Override
- protected native void finalize() throws Throwable;
+ @Override
+ protected native void finalize() throws Throwable;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs
index 3ce691775c..aaab1fe9f1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property.java.ejs
@@ -2,6 +2,7 @@
const properties = locals.properties;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.StringDef;
@@ -12,56 +13,49 @@ import java.lang.annotation.RetentionPolicy;
/**
* Paint/Layout properties for Layer
*/
-public abstract class Property<T> {
-
- //VISIBILITY: Whether this layer is displayed.
-
- /**
- * The layer is shown.
- */
- public static final String VISIBLE = "visible";
- /**
- * The layer is hidden.
- */
- public static final String NONE = "none";
-
- @StringDef({
- VISIBLE,
- NONE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface VISIBILITY {}
+public final class Property {
+
+ // VISIBILITY: Whether this layer is displayed.
+
+ /**
+ * The layer is shown.
+ */
+ public static final String VISIBLE = "visible";
+ /**
+ * The layer is hidden.
+ */
+ public static final String NONE = "none";
+
+ @StringDef({
+ VISIBLE,
+ NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VISIBILITY {}
<% for (const property of properties) { -%>
- //<%- snakeCaseUpper(property.name) %>: <%- property.doc %>
+ // <%- snakeCaseUpper(property.name) %>: <%- property.doc %>
<% for (const value in property.values) { -%>
- /**
- * <%- propertyValueDoc(property, value) %>
- */
- public static final String <%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %> = "<%- value %>";
+ /**
+ * <%- propertyValueDoc(property, value) %>
+ */
+ public static final String <%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %> = "<%- value %>";
<% } -%>
- /**
- * <%- property.doc %>
- */
- @StringDef({
- <% for (const value of Object.keys(property.values)) { -%>
- <%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %>,
- <% } -%>
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface <%- snakeCaseUpper(property.name) %> {}
+ /**
+ * <%- property.doc %>
+ */
+ @StringDef({
+ <% for (const value of Object.keys(property.values)) { -%>
+ <%- snakeCaseUpper(property.name) %>_<%- snakeCaseUpper(value) %>,
+ <% } -%>
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface <%- snakeCaseUpper(property.name) %> {}
<% } -%>
- //Class definition
- public final String name;
- public final T value;
-
- /* package */ Property(String name, T value) {
- this.name = name;
- this.value = value;
- }
-
+ private Property() {
+ }
}
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 e9b7b6dcd1..2d3421d1d9 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
@@ -3,11 +3,15 @@
const layoutProperties = locals.layoutProperties;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
package com.mapbox.mapboxsdk.style.layers;
import android.annotation.SuppressLint;
import android.support.annotation.ColorInt;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+
/**
* Constructs paint/layout properties for Layers
*
@@ -15,85 +19,121 @@ import android.support.annotation.ColorInt;
*/
public class PropertyFactory {
- /**
- * Set the property visibility.
- *
- * @param value the visibility value
- * @return property wrapper around visibility
- */
- public static Property<String> visibility(@Property.VISIBILITY String value) {
- return new LayoutProperty<>("visibility", value);
- }
-
- /**
- * Set the property visibility.
- *
- * @param function the visibility function
- * @return property wrapper around a String function
- */
- public static Property<Function<String>> visibility(Function<String> function) {
- return new LayoutProperty<>("visibility", function);
- }
+ /**
+ * Set the property visibility.
+ *
+ * @param value the visibility value
+ * @return property wrapper around visibility
+ */
+ public static PropertyValue<String> visibility(@Property.VISIBILITY String value) {
+ return new LayoutPropertyValue<>("visibility", value);
+ }
+
+ /**
+ * Set the property visibility.
+ *
+ * @param <T> the function input type
+ * @param function the visibility function
+ * @return property wrapper around a String function
+ */
+ public static <T> PropertyValue<Function<T, String>> visibility(Function<T, String> function) {
+ return new LayoutPropertyValue<>("visibility", function);
+ }
<% for (const property of paintProperties) { -%>
<% if (property.type == 'color') { -%>
- /**
- * <%- propertyFactoryMethodDoc(property) %>
- *
- * @param value a int color value
- * @return property wrapper around String color
- */
- public static Property<String> <%- camelizeWithLeadingLowercase(property.name) %>(@ColorInt int value) {
- return new PaintProperty<>("<%- property.name %>", colorToRgbaString(value));
- }
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param value a int color value
+ * @return property wrapper around String color
+ */
+ public static PropertyValue<String> <%- camelizeWithLeadingLowercase(property.name) %>(@ColorInt int value) {
+ return new PaintPropertyValue<>("<%- property.name %>", colorToRgbaString(value));
+ }
<% } -%>
- /**
- * <%- propertyFactoryMethodDoc(property) %>
- *
- * @param value a <%- propertyType(property) %> value
- * @return property wrapper around <%- propertyType(property) %>
- */
- public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
- return new PaintProperty<>("<%- property.name %>", value);
- }
-
- /**
- * <%- propertyFactoryMethodDoc(property) %>
- *
- * @param function a wrapper function for <%- propertyType(property) %>
- * @return property wrapper around a <%- propertyType(property) %> function
- */
- public static Property<Function<<%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<<%- propertyType(property) %>> function) {
- return new PaintProperty<>("<%- property.name %>", function);
- }
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param value a <%- propertyType(property) %> value
+ * @return property wrapper around <%- propertyType(property) %>
+ */
+ public static PropertyValue<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
+ return new PaintPropertyValue<>("<%- property.name %>", value);
+ }
+
+<% if (supportsPropertyFunction(property)) { -%>
+
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for <%- propertyType(property) %>
+ * @return property wrapper around a <%- propertyType(property) %> function
+ */
+ public static <T> PropertyValue<Function<T, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<T, <%- propertyType(property) %>> function) {
+ return new PaintPropertyValue<>("<%- property.name %>", function);
+ }
+
+<% } else if (supportsZoomFunction(property)) { -%>
+
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for <%- propertyType(property) %>
+ * @return property wrapper around a <%- propertyType(property) %> function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(CameraFunction<Z, <%- propertyType(property) %>> function) {
+ return new PaintPropertyValue<>("<%- property.name %>", function);
+ }
<% } -%>
+<% } -%>
<% for (const property of layoutProperties) { -%>
- /**
- * <%- propertyFactoryMethodDoc(property) %>
- *
- * @param value a <%- propertyType(property) %> value
- * @return property wrapper around <%- propertyType(property) %>
- */
- public static Property<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
- return new LayoutProperty<>("<%- property.name %>", value);
- }
-
- /**
- * <%- propertyFactoryMethodDoc(property) %>
- *
- * @param function a wrapper function for <%- propertyType(property) %>
- * @return property wrapper around a <%- propertyType(property) %> function
- */
- public static Property<Function<<%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<<%- propertyType(property) %>> function) {
- return new LayoutProperty<>("<%- property.name %>", function);
- }
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param value a <%- propertyType(property) %> value
+ * @return property wrapper around <%- propertyType(property) %>
+ */
+ public static PropertyValue<<%- propertyType(property) %>> <%- camelizeWithLeadingLowercase(property.name) %>(<%- propertyTypeAnnotation(property) %><%- iff(() => propertyTypeAnnotation(property), " ") %><%- propertyType(property) %> value) {
+ return new LayoutPropertyValue<>("<%- property.name %>", value);
+ }
+
+
+<% if (supportsPropertyFunction(property)) { -%>
+
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for <%- propertyType(property) %>
+ * @return property wrapper around a <%- propertyType(property) %> function
+ */
+ public static <T> PropertyValue<Function<T, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<T, <%- propertyType(property) %>> function) {
+ return new LayoutPropertyValue<>("<%- property.name %>", function);
+ }
+<% } else if (supportsZoomFunction(property)) { -%>
+
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for <%- propertyType(property) %>
+ * @return property wrapper around a <%- propertyType(property) %> function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(CameraFunction<Z, <%- propertyType(property) %>> function) {
+ return new LayoutPropertyValue<>("<%- property.name %>", function);
+ }
+
+<% } -%>
<% } -%>
- @SuppressLint("DefaultLocale")
- static String colorToRgbaString(@ColorInt int value) {
- return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
- }
+ @SuppressLint("DefaultLocale")
+ public static String colorToRgbaString(@ColorInt int value) {
+ return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
+ }
}
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 0c2ee42ea0..f9875c7242 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
@@ -160,8 +160,8 @@ public class GeoJsonSource extends Source {
}
protected void setRawJson(String geoJson) {
- //Wrap the String in a map as an Object is expected by the
- //style conversion template
+ // Wrap the String in a map as an Object is expected by the
+ // style conversion template
HashMap<String, String> wrapper = new HashMap<>();
wrapper.put("data", geoJson);
nativeSetGeoJson(wrapper);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/NoSuchSourceException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/NoSuchSourceException.java
deleted file mode 100644
index 06d35b598b..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/NoSuchSourceException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.mapbox.mapboxsdk.style.sources;
-
-/**
- * No such source.
- */
-public class NoSuchSourceException extends Exception {
-
- public NoSuchSourceException(String message) {
- super(message);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java
new file mode 100644
index 0000000000..4a97d71f9a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/UnknownSource.java
@@ -0,0 +1,25 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import android.support.annotation.UiThread;
+
+/**
+ * An unknown type of source
+ */
+@UiThread
+public class UnknownSource extends Source {
+
+ /**
+ * Creates a UnknownSource.
+ *
+ * @param nativePtr pointer used by core
+ */
+ UnknownSource(long nativePtr) {
+ super(nativePtr);
+ }
+
+ protected native void initialize();
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java
deleted file mode 100644
index 8457d24ff2..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/GzipRequestInterceptor.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import timber.log.Timber;
-
-import java.io.IOException;
-
-import okhttp3.Interceptor;
-import okhttp3.MediaType;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okio.BufferedSink;
-import okio.GzipSink;
-import okio.Okio;
-
-/**
- * OkHttp Interceptor for Gzipping Telemetry Data requests to the server.
- * Based on: https://github.com/square/okhttp/wiki/Interceptors
- */
-public final class GzipRequestInterceptor implements Interceptor {
-
- @Override
- public Response intercept(Interceptor.Chain chain) throws IOException {
- Request originalRequest = chain.request();
- if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
- Timber.d("Not compressing");
- return chain.proceed(originalRequest);
- }
-
- Timber.d("Compressing");
- Request compressedRequest = originalRequest.newBuilder()
- .header("Content-Encoding", "gzip")
- .method(originalRequest.method(), gzip(originalRequest.body()))
- .build();
- return chain.proceed(compressedRequest);
- }
-
- private RequestBody gzip(final RequestBody body) {
- return new RequestBody() {
- @Override
- public MediaType contentType() {
- return body.contentType();
- }
-
- @Override
- public long contentLength() {
- return -1; // We don't know the compressed length in advance!
- }
-
- @Override
- public void writeTo(BufferedSink sink) throws IOException {
- BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
- body.writeTo(gzipSink);
- gzipSink.close();
- }
- };
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
deleted file mode 100644
index b5203bc02a..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEvent.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import android.graphics.PointF;
-import android.support.annotation.NonNull;
-
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.Projection;
-
-import java.io.Serializable;
-import java.util.Hashtable;
-
-import timber.log.Timber;
-
-/**
- * Constants for Telemetry Metadata
- */
-public class MapboxEvent implements Serializable {
- public static final int VERSION_NUMBER = 2;
- public static final String MAPBOX_EVENTS_BASE_URL = "https://events.mapbox.com";
- public static final String SOURCE_MAPBOX = "mapbox";
-
- // Event Types
- public static final String TYPE_TURNSTILE = "appUserTurnstile";
- public static final String TYPE_MAP_LOAD = "map.load";
- public static final String TYPE_MAP_CLICK = "map.click";
- public static final String TYPE_MAP_DRAGEND = "map.dragend";
- public static final String TYPE_LOCATION = "location";
- public static final String TYPE_VISIT = "visit";
-
- // Event Keys
- public static final String KEY_LATITUDE = "lat";
- public static final String KEY_LONGITUDE = "lng";
- public static final String KEY_SPEED = "speed";
- public static final String KEY_COURSE = "course";
- public static final String KEY_ALTITUDE = "altitude";
- public static final String KEY_HORIZONTAL_ACCURACY = "horizontalAccuracy";
- public static final String KEY_ZOOM = "zoom";
-
- public static final String KEY_PUSH_ENABLED = "enabled.push";
- public static final String KEY_EMAIL_ENABLED = "enabled.email";
- public static final String KEY_GESTURE_ID = "gesture";
- public static final String KEY_ARRIVAL_DATE = "arrivalDate";
- public static final String KEY_DEPARTURE_DATE = "departureDate";
-
- public static final String GESTURE_SINGLETAP = "SingleTap";
- public static final String GESTURE_DOUBLETAP = "DoubleTap";
- public static final String GESTURE_TWO_FINGER_SINGLETAP = "TwoFingerTap";
- public static final String GESTURE_QUICK_ZOOM = "QuickZoom";
- public static final String GESTURE_PAN_START = "Pan";
- public static final String GESTURE_PINCH_START = "Pinch";
- public static final String GESTURE_ROTATION_START = "Rotation";
- public static final String GESTURE_PITCH_START = "Pitch";
-
- // Event Attributes
- public static final String ATTRIBUTE_EVENT = "event";
- public static final String ATTRIBUTE_USERID = "userId";
- public static final String ATTRIBUTE_SOURCE = "source";
- public static final String ATTRIBUTE_ENABLED_TELEMETRY = "enabled.telemetry";
- public static final String ATTRIBUTE_SESSION_ID = "sessionId";
- public static final String ATTRIBUTE_VERSION = "version";
- public static final String ATTRIBUTE_CREATED = "created";
- public static final String ATTRIBUTE_VENDOR_ID = "vendorId";
- public static final String ATTRIBUTE_APP_BUNDLE_ID = "appBundleId";
- public static final String ATTRIBUTE_MODEL = "model";
- public static final String ATTRIBUTE_OPERATING_SYSTEM = "operatingSystem";
- public static final String ATTRIBUTE_ORIENTATION = "orientation";
- public static final String ATTRIBUTE_BATTERY_LEVEL = "batteryLevel";
- public static final String ATTRIBUTE_PLUGGED_IN = "pluggedIn";
- public static final String ATTRIBUTE_APPLICATION_STATE = "applicationState";
- public static final String ATTRIBUTE_RESOLUTION = "resolution";
- public static final String ATTRIBUTE_ACCESSIBILITY_FONT_SCALE = "accessibilityFontScale";
- public static final String ATTRIBUTE_CARRIER = "carrier";
- public static final String ATTRIBUTE_CELLULAR_NETWORK_TYPE = "cellularNetworkType";
- public static final String ATTRIBUTE_WIFI = "wifi";
-
- /**
- * Helper method for tracking gesture events
- *
- * @param projection Projection of the Map object
- * @param gestureId Type of Gesture See {@see MapboxEvent#GESTURE_SINGLETAP
- * MapboxEvent#GESTURE_DOUBLETAP
- * MapboxEvent#GESTURE_TWO_FINGER_SINGLETAP
- * MapboxEvent#GESTURE_QUICK_ZOOM
- * MapboxEvent#GESTURE_PAN_START
- * MapboxEvent#GESTURE_PINCH_START
- * MapboxEvent#GESTURE_ROTATION_START
- * MapboxEvent#GESTURE_PITCH_START}
- * @param xCoordinate Original x screen coordinate at start of gesture
- * @param yCoordinate Original y screen cooridnate at start of gesture
- * @param zoom Zoom level to be registered
- */
- public static void trackGestureEvent(@NonNull Projection projection, @NonNull String gestureId, float xCoordinate,
- float yCoordinate, double zoom) {
- LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
-
- // NaN and Infinite checks to prevent JSON errors at send to server time
- if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
- Timber.d("trackGestureEvent() has a NaN lat or lon. Returning.");
- return;
- }
-
- if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
- Timber.d("trackGestureEvent() has an Infinite lat or lon. Returning.");
- return;
- }
-
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_CLICK);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- evt.put(MapboxEvent.KEY_GESTURE_ID, gestureId);
- evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude());
- evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude());
- evt.put(MapboxEvent.KEY_ZOOM, zoom);
-
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
-
- /**
- * Helper method for tracking DragEnd gesture event
- * See {@see MapboxEvent#TYPE_MAP_DRAGEND}
- *
- * @param projection projection of the Map object.
- * @param xCoordinate Original x screen coordinate at end of drag
- * @param yCoordinate Orginal y screen coordinate at end of drag
- * @param zoom Zoom level to be registered
- */
- public static void trackGestureDragEndEvent(@NonNull Projection projection, float xCoordinate, float yCoordinate,
- double zoom) {
- LatLng tapLatLng = projection.fromScreenLocation(new PointF(xCoordinate, yCoordinate));
-
- // NaN and Infinite checks to prevent JSON errors at send to server time
- if (Double.isNaN(tapLatLng.getLatitude()) || Double.isNaN(tapLatLng.getLongitude())) {
- Timber.d("trackGestureDragEndEvent() has a NaN lat or lon. Returning.");
- return;
- }
-
- if (Double.isInfinite(tapLatLng.getLatitude()) || Double.isInfinite(tapLatLng.getLongitude())) {
- Timber.d("trackGestureDragEndEvent() has an Infinite lat or lon. Returning.");
- return;
- }
-
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_DRAGEND);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- evt.put(MapboxEvent.KEY_LATITUDE, tapLatLng.getLatitude());
- evt.put(MapboxEvent.KEY_LONGITUDE, tapLatLng.getLongitude());
- evt.put(MapboxEvent.KEY_ZOOM, zoom);
-
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
-
- /**
- * Helper method for tracking map load event
- */
- public static void trackMapLoadEvent() {
- Hashtable<String, Object> evt = new Hashtable<>();
- evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_LOAD);
- evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate());
- MapboxEventManager.getMapboxEventManager().pushEvent(evt);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
deleted file mode 100644
index 4a0ef248b7..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/MapboxEventManager.java
+++ /dev/null
@@ -1,828 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.content.res.Configuration;
-import android.location.Location;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.os.AsyncTask;
-import android.os.BatteryManager;
-import android.os.Build;
-import android.os.Handler;
-import android.support.annotation.NonNull;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-
-import com.mapbox.mapboxsdk.BuildConfig;
-import com.mapbox.mapboxsdk.Mapbox;
-import com.mapbox.mapboxsdk.constants.GeoConstants;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.exceptions.TelemetryServiceNotConfiguredException;
-import com.mapbox.mapboxsdk.location.LocationServices;
-import com.mapbox.mapboxsdk.utils.MathUtils;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-import java.util.UUID;
-import java.util.Vector;
-
-import okhttp3.CertificatePinner;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-import okhttp3.internal.Util;
-import timber.log.Timber;
-
-/**
- * Singleton control center for managing Telemetry Data.
- * Primary access is via MapboxEventManager.getMapboxEventManager()
- */
-public class MapboxEventManager {
-
- private static MapboxEventManager mapboxEventManager = null;
-
- private boolean initialized = false;
- private boolean stagingEnv;
- private boolean telemetryEnabled;
-
- private final Vector<Hashtable<String, Object>> events = new Vector<>();
- private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
- private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",
- MapboxConstants.MAPBOX_LOCALE);
-
- private Context context = null;
- private String accessToken = null;
- private String eventsURL = MapboxEvent.MAPBOX_EVENTS_BASE_URL;
-
- private String userAgent = BuildConfig.MAPBOX_EVENTS_USER_AGENT_BASE;
-
- private Intent batteryStatus = null;
- private final String operatingSystem = "Android - " + Build.VERSION.RELEASE;
-
- private DisplayMetrics displayMetrics = null;
-
- private String mapboxVendorId = null;
-
- private String mapboxSessionId = null;
- private long mapboxSessionIdLastSet = 0;
- private static long hourInMillis = 1000 * 60 * 60;
- private static long flushDelayInitialInMillis = 1000 * 10; // 10 Seconds
- private static long flushDelayInMillis = 1000 * 60 * 3; // 3 Minutes
- private static final int SESSION_ID_ROTATION_HOURS = 24;
-
- private static final int FLUSH_EVENTS_CAP = 1000;
-
- private static MessageDigest messageDigest = null;
-
- private static final double locationEventAccuracy = 10000000;
-
- private Timer timer = null;
-
- /**
- * Private Constructor for configuring the single instance per app.
- */
- private MapboxEventManager() {
- super();
- }
-
- /**
- * Internal setup of MapboxEventsManager. It needs to be called once before @link
- * MapboxEventManager#getMapboxEventManager
- * <p>
- * This allows for a cleaner getMapboxEventManager() that doesn't require context and accessToken
- *
- * @param context The context associated with MapView
- * @param accessToken The accessToken to load MapView
- */
- public void initialize(@NonNull Context context, @NonNull String accessToken) {
-
- //Timber.i("Telemetry initialize() called...");
-
- if (initialized) {
- //Timber.i("Mapbox Telemetry has already been initialized.");
- return;
- }
-
- this.context = context.getApplicationContext();
- this.accessToken = accessToken;
-
- validateTelemetryServiceConfigured();
-
- // Setup Message Digest
- try {
- messageDigest = MessageDigest.getInstance("SHA-1");
- } catch (NoSuchAlgorithmException exception) {
- Timber.w("Error getting Encryption Algorithm: ", exception);
- }
-
- // Create Initial Session Id
- rotateSessionId();
-
- SharedPreferences prefs = context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES_FILE,
- Context.MODE_PRIVATE);
-
- // Determine if Telemetry Should Be Enabled
- ///Timber.i("Right before Telemetry set enabled in initialized()");
- setTelemetryEnabled(prefs.getBoolean(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED, true));
-
- // Load / Create Vendor Id
- if (prefs.contains(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID)) {
- mapboxVendorId = prefs.getString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID, "");
- }
- if (TextUtils.isEmpty(mapboxVendorId)) {
- String vendorId = UUID.randomUUID().toString();
- mapboxVendorId = encodeString(vendorId);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_VENDORID, mapboxVendorId);
- editor.apply();
- editor.commit();
- }
-
- // Get DisplayMetrics Setup
- displayMetrics = new DisplayMetrics();
- ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(displayMetrics);
-
- // Check for Staging Server Information
- try {
- ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(),
- PackageManager.GET_META_DATA);
- String stagingURL = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_SERVER);
- String stagingAccessToken = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_STAGING_ACCESS_TOKEN);
-
- if (TextUtils.isEmpty(stagingURL) || TextUtils.isEmpty(stagingAccessToken)) {
- //Timber.d("Looking in SharedPreferences for Staging Credentials");
- stagingURL = prefs.getString(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL, null);
- stagingAccessToken = prefs.getString(
- MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN, null);
- }
-
- if (!TextUtils.isEmpty(stagingURL) && !TextUtils.isEmpty(stagingAccessToken)) {
- eventsURL = stagingURL;
- this.accessToken = accessToken;
- stagingEnv = true;
- }
-
- // Build User Agent
- String appIdentifier = getApplicationIdentifier();
- if (TextUtils.equals(userAgent, BuildConfig.MAPBOX_EVENTS_USER_AGENT_BASE) && !TextUtils.isEmpty(appIdentifier)) {
- userAgent = Util
- .toHumanReadableAscii(String.format(MapboxConstants.MAPBOX_LOCALE, "%s %s", appIdentifier, userAgent));
- }
-
- } catch (Exception exception) {
- //Timber.e("Error Trying to load Staging Credentials: ", exception);
- }
-
- // Register for battery updates
- IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- batteryStatus = context.registerReceiver(null, iFilter);
-
- initialized = true;
- }
-
- /**
- * Primary Access method using Singleton pattern
- *
- * @return MapboxEventManager
- */
- public static MapboxEventManager getMapboxEventManager() {
- if (mapboxEventManager == null) {
- mapboxEventManager = new MapboxEventManager();
- }
- return mapboxEventManager;
- }
-
- // Checks that TelemetryService has been configured by developer
- private void validateTelemetryServiceConfigured() {
- try {
- // Check Implementing app's AndroidManifest.xml
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(),
- PackageManager.GET_SERVICES);
- if (packageInfo.services != null) {
- for (ServiceInfo service : packageInfo.services) {
- if (TextUtils.equals("com.mapbox.mapboxsdk.telemetry.TelemetryService", service.name)) {
- return;
- }
- }
- }
- } catch (Exception exception) {
- //Timber.w("Error checking for Telemetry Service Config: ", exception);
- }
- throw new TelemetryServiceNotConfiguredException();
- }
-
- public static String generateCreateDate() {
- return dateFormat.format(new Date());
- }
-
- public boolean isTelemetryEnabled() {
- return telemetryEnabled;
- }
-
- /**
- * Enables / Disables Telemetry
- *
- * @param telemetryEnabled True to start telemetry, false to stop it
- */
- public void setTelemetryEnabled(boolean telemetryEnabled) {
- //Timber.i("this.telemetryEnabled = " + this.telemetryEnabled + "; telemetryEnabled = " + telemetryEnabled);
- if (this.telemetryEnabled == telemetryEnabled) {
- //Timber.d("No need to start / stop telemetry as it's already in that state.");
- return;
- }
-
- if (telemetryEnabled) {
- //Timber.d("Starting Telemetry Up!");
- // Start It Up
- context.startService(new Intent(context, TelemetryService.class));
-
- // Make sure Ambient Mode is started at a minimum
- if (LocationServices.getLocationServices(context).areLocationPermissionsGranted()) {
- //Timber.i("Permissions are good, see if GPS is enabled and if not then setup Ambient.");
- if (LocationServices.getLocationServices(context).isGpsEnabled()) {
- LocationServices.getLocationServices(context).toggleGPS(false);
- }
- } else {
- // Start timer that checks for Permissions
- //Timber.i("Permissions are not good. Need to do some looping to check on stuff.");
-
- final Handler permsHandler = new Handler();
- Runnable runnable = new Runnable() {
-
- private final ExponentialBackoffCounter exponentialBackoffCounter = new ExponentialBackoffCounter();
-
- @Override
- public void run() {
- if (LocationServices.getLocationServices(context).areLocationPermissionsGranted()) {
- //Timber.i("Permissions finally granted, so starting Ambient if GPS isn't already enabled");
- // Start Ambient
- if (LocationServices.getLocationServices(context).isGpsEnabled()) {
- LocationServices.getLocationServices(context).toggleGPS(false);
- }
- } else {
- // Restart Handler
- long nextWaitTime = exponentialBackoffCounter.getNextCount();
- //Timber.i("Permissions not granted yet... let's try again in " + nextWaitTime/1000 + " seconds");
- permsHandler.postDelayed(this, nextWaitTime);
- }
- }
- };
- permsHandler.postDelayed(runnable, 1000 * 10);
- }
-
- // Manage Timer Flush
- timer = new Timer();
- timer.schedule(new FlushEventsTimerTask(), flushDelayInitialInMillis, flushDelayInMillis);
- } else {
- //Timber.d("Shutting Telemetry Down");
- // Shut It Down
- events.removeAllElements();
- context.stopService(new Intent(context, TelemetryService.class));
-
- if (timer != null) {
- timer.cancel();
- timer = null;
- }
- }
-
- // Persist
- this.telemetryEnabled = telemetryEnabled;
- SharedPreferences prefs = context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES_FILE,
- Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(MapboxConstants.MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED, telemetryEnabled);
- editor.apply();
- editor.commit();
- }
-
- /**
- * Immediately attempt to send all events data in the queue to the server.
- * <p>
- * NOTE: Permission set to package private to enable only telemetry code to use this.
- */
- void flushEventsQueueImmediately() {
- //Timber.i("flushEventsQueueImmediately() called...");
- new FlushTheEventsTask().execute();
- }
-
- /**
- * Centralized method for adding populated event to the queue allowing for cap size checking
- *
- * @param event Event to add to the Events Queue
- */
- private void putEventOnQueue(@NonNull Hashtable<String, Object> event) {
- if (event == null) {
- return;
- }
- events.add(event);
- if (events.size() == FLUSH_EVENTS_CAP) {
- //Timber.d("eventsSize == flushCap so send data.");
- flushEventsQueueImmediately();
- }
- }
-
- /**
- * Adds a Location Event to the system for processing
- *
- * @param location Location event
- */
- public void addLocationEvent(Location location) {
-
- // NaN and Infinite checks to prevent JSON errors at send to server time
- if (Double.isNaN(location.getLatitude()) || Double.isNaN(location.getLongitude())
- || Double.isNaN(location.getAltitude()) || Float.isNaN(location.getAccuracy())) {
- return;
- }
-
- if (Double.isInfinite(location.getLatitude()) || Double.isInfinite(location.getLongitude())
- || Double.isInfinite(location.getAltitude()) || Float.isInfinite(location.getAccuracy())) {
- return;
- }
-
- // Add Location even to queue
- Hashtable<String, Object> event = new Hashtable<>();
- event.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_LOCATION);
- event.put(MapboxEvent.ATTRIBUTE_CREATED, generateCreateDate());
- event.put(MapboxEvent.ATTRIBUTE_SOURCE, MapboxEvent.SOURCE_MAPBOX);
- event.put(MapboxEvent.ATTRIBUTE_SESSION_ID, encodeString(mapboxSessionId));
- event.put(MapboxEvent.KEY_LATITUDE,
- Math.floor(location.getLatitude() * locationEventAccuracy) / locationEventAccuracy);
- event.put(MapboxEvent.KEY_LONGITUDE,
- Math.floor(location.getLongitude() * locationEventAccuracy) / locationEventAccuracy);
- event.put(MapboxEvent.KEY_ALTITUDE, location.getAltitude());
- event.put(MapboxEvent.KEY_HORIZONTAL_ACCURACY, Math.round(location.getAccuracy()));
- event.put(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM, operatingSystem);
- event.put(MapboxEvent.ATTRIBUTE_APPLICATION_STATE, getApplicationState());
-
- putEventOnQueue(event);
-
- rotateSessionId();
- }
-
- /**
- * Push Interactive Events to the system for processing
- *
- * @param eventWithAttributes Event with attributes
- */
- public void pushEvent(Hashtable<String, Object> eventWithAttributes) {
- if (context == null || accessToken == null) {
- return;
- }
-
- if (eventWithAttributes == null) {
- return;
- }
-
- String eventType = (String) eventWithAttributes.get(MapboxEvent.ATTRIBUTE_EVENT);
- if (TextUtils.isEmpty(eventType)) {
- return;
- }
-
- if (eventType.equalsIgnoreCase(MapboxEvent.TYPE_MAP_LOAD)) {
- // Map Load Data Model
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_USERID, mapboxVendorId);
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_MODEL, Build.MODEL);
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM, operatingSystem);
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_RESOLUTION, displayMetrics.density);
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_ACCESSIBILITY_FONT_SCALE, getAccesibilityFontScaleSize());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_ORIENTATION, getOrientation());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL, getBatteryLevel());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_PLUGGED_IN, isPluggedIn());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CARRIER, getCellularCarrier());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE, getCellularNetworkType());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_WIFI, getConnectedToWifi());
-
- // Put Map Load on events before Turnstile clears it
- putEventOnQueue(eventWithAttributes);
-
- // Turnstile
- pushTurnstileEvent();
-
- // Return immediately to avoid double adding of event
- return;
-
- } else if (eventType.equalsIgnoreCase(MapboxEvent.TYPE_MAP_CLICK)) {
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_ORIENTATION, getOrientation());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL, getBatteryLevel());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_PLUGGED_IN, isPluggedIn());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CARRIER, getCellularCarrier());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE, getCellularNetworkType());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_WIFI, getConnectedToWifi());
- } else if (eventType.equalsIgnoreCase(MapboxEvent.TYPE_MAP_DRAGEND)) {
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_ORIENTATION, getOrientation());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL, getBatteryLevel());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_PLUGGED_IN, isPluggedIn());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CARRIER, getCellularCarrier());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE, getCellularNetworkType());
- eventWithAttributes.put(MapboxEvent.ATTRIBUTE_WIFI, getConnectedToWifi());
- } else {
- //Timber.w("This is not an event type in the Events Data Model.");
- return;
- }
-
- putEventOnQueue(eventWithAttributes);
- }
-
- /**
- * Pushes turnstile event for internal billing purposes
- */
- private void pushTurnstileEvent() {
-
- Hashtable<String, Object> event = new Hashtable<>();
- event.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_TURNSTILE);
- event.put(MapboxEvent.ATTRIBUTE_CREATED, generateCreateDate());
- event.put(MapboxEvent.ATTRIBUTE_USERID, mapboxVendorId);
- event.put(MapboxEvent.ATTRIBUTE_ENABLED_TELEMETRY, telemetryEnabled);
-
- events.add(event);
-
- // Send to Server Immediately
- flushEventsQueueImmediately();
- //Timber.d("turnstile event pushed.");
- }
-
- /**
- * SHA-1 Encoding for strings
- *
- * @param string String to encode
- * @return String encoded if no error, original string if error
- */
- private String encodeString(String string) {
- try {
- if (messageDigest != null) {
- messageDigest.reset();
- messageDigest.update(string.getBytes("UTF-8"));
- byte[] bytes = messageDigest.digest();
-
- // Get the Hex version of the digest
- StringBuilder sb = new StringBuilder();
- for (byte b : bytes) {
- sb.append(String.format("%02X", b));
- }
- String hex = sb.toString();
-
- return hex;
- }
- } catch (Exception exception) {
- //Timber.w("Error encoding string, will return in original form.", exception);
- }
- return string;
- }
-
- /**
- * Changes Session Id based on time boundary
- */
- private void rotateSessionId() {
- long now = System.currentTimeMillis();
- if ((TextUtils.isEmpty(mapboxSessionId))
- || (now - mapboxSessionIdLastSet > (SESSION_ID_ROTATION_HOURS * hourInMillis))) {
- mapboxSessionId = UUID.randomUUID().toString();
- mapboxSessionIdLastSet = System.currentTimeMillis();
- }
- }
-
- private String getOrientation() {
- switch (context.getResources().getConfiguration().orientation) {
- case Configuration.ORIENTATION_LANDSCAPE:
- return "Landscape";
- case Configuration.ORIENTATION_PORTRAIT:
- return "Portrait";
- default:
- return "";
- }
- }
-
- private int getBatteryLevel() {
- int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
-
- return Math.round((level / (float) scale) * 100);
- }
-
- /**
- * Determine if device is plugged in to power via USB or AC or not.
- * <p>
- * http://developer.android.com/reference/android/os/BatteryManager.html#EXTRA_PLUGGED
- *
- * @return true if plugged in, false if not
- */
- private boolean isPluggedIn() {
-
- int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
- if (chargePlug == BatteryManager.BATTERY_PLUGGED_USB || chargePlug == BatteryManager.BATTERY_PLUGGED_AC) {
- return true;
- }
-
- return false;
- }
-
- private String getApplicationState() {
-
- ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
- if (appProcesses == null) {
- return "";
- }
- final String packageName = context.getPackageName();
- for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
- if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
- && appProcess.processName.equals(packageName)) {
- return "Foreground";
- }
- }
- return "Background";
- }
-
- private float getAccesibilityFontScaleSize() {
- // Values
- // Small = 0.85
- // Normal = 1.0
- // Large = 1.15
- // Huge = 1.3
-
- return context.getResources().getConfiguration().fontScale;
- }
-
- private String getCellularCarrier() {
- TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- String carrierName = manager.getNetworkOperatorName();
- if (TextUtils.isEmpty(carrierName)) {
- carrierName = "";
- }
- return carrierName;
- }
-
- private String getCellularNetworkType() {
- TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- switch (manager.getNetworkType()) {
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- return "1xRTT";
- case TelephonyManager.NETWORK_TYPE_CDMA:
- return "CDMA";
- case TelephonyManager.NETWORK_TYPE_EDGE:
- return "EDGE";
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- return "EHRPD";
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- return "EVDO_0";
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- return "EVDO_A";
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- return "EVDO_B";
- case TelephonyManager.NETWORK_TYPE_GPRS:
- return "GPRS";
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- return "HSDPA";
- case TelephonyManager.NETWORK_TYPE_HSPA:
- return "HSPA";
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- return "HSPAP";
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- return "HSUPA";
- case TelephonyManager.NETWORK_TYPE_IDEN:
- return "IDEN";
- case TelephonyManager.NETWORK_TYPE_LTE:
- return "LTE";
- case TelephonyManager.NETWORK_TYPE_UMTS:
- return "UMTS";
- case TelephonyManager.NETWORK_TYPE_UNKNOWN:
- return "Unknown";
- default:
- return "";
- }
- }
-
- public Boolean getConnectedToWifi() {
-
- Boolean status = false;
- WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- if (wifiMgr.isWifiEnabled()) {
- try {
- WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
- if (wifiInfo.getNetworkId() != -1) {
- status = true;
- }
- } catch (Exception exception) {
- //Timber.w("Error getting Wifi Connection Status: ", exception);
- status = false;
- }
- }
-
- return status;
- }
-
-
- /**
- * Task responsible for converting stored events and sending them to the server
- */
- private class FlushTheEventsTask extends AsyncTask<Void, Void, Void> {
-
- @Override
- protected Void doInBackground(Void... voids) {
-
- if (events.isEmpty()) {
- //Timber.d("No events in the queue to send so returning.");
- return null;
- }
-
- // Check for NetworkConnectivity
- if (!Mapbox.isConnected()) {
- //Timber.w("Not connected to network, so empty events cache and return without attempting to send events");
- // Make sure that events don't pile up when Offline
- // and thus impact available memory over time.
- events.removeAllElements();
- return null;
- }
-
- Response response = null;
-
- try {
- // Send data
- // =========
- JSONArray jsonArray = new JSONArray();
-
- Vector<Hashtable<String, Object>> eventsClone = (Vector<Hashtable<String, Object>>) events.clone();
-
- for (Hashtable<String, Object> evt : eventsClone) {
- JSONObject jsonObject = new JSONObject();
-
- // Build the JSON but only if there's a value for it in the evt
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_EVENT, evt.get(MapboxEvent.ATTRIBUTE_EVENT));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_CREATED, evt.get(MapboxEvent.ATTRIBUTE_CREATED));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_USERID, evt.get(MapboxEvent.ATTRIBUTE_USERID));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_ENABLED_TELEMETRY, evt.get(MapboxEvent.ATTRIBUTE_ENABLED_TELEMETRY));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_SOURCE, evt.get(MapboxEvent.ATTRIBUTE_SOURCE));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_SESSION_ID, evt.get(MapboxEvent.ATTRIBUTE_SESSION_ID));
- jsonObject.putOpt(MapboxEvent.KEY_LATITUDE, evt.get(MapboxEvent.KEY_LATITUDE));
-
- // Make sure Longitude Is Wrapped
- if (evt.containsKey(MapboxEvent.KEY_LONGITUDE)) {
- double lon = (double) evt.get(MapboxEvent.KEY_LONGITUDE);
- if ((lon < GeoConstants.MIN_LONGITUDE) || (lon > GeoConstants.MAX_LONGITUDE)) {
- lon = MathUtils.wrap(lon, GeoConstants.MIN_LONGITUDE, GeoConstants.MAX_LONGITUDE);
- }
- jsonObject.put(MapboxEvent.KEY_LONGITUDE, lon);
- }
-
- jsonObject.putOpt(MapboxEvent.KEY_ALTITUDE, evt.get(MapboxEvent.KEY_ALTITUDE));
- jsonObject.putOpt(MapboxEvent.KEY_ZOOM, evt.get(MapboxEvent.KEY_ZOOM));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM, evt.get(MapboxEvent.ATTRIBUTE_OPERATING_SYSTEM));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_USERID, evt.get(MapboxEvent.ATTRIBUTE_USERID));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_MODEL, evt.get(MapboxEvent.ATTRIBUTE_MODEL));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_RESOLUTION, evt.get(MapboxEvent.ATTRIBUTE_RESOLUTION));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_ACCESSIBILITY_FONT_SCALE,
- evt.get(MapboxEvent.ATTRIBUTE_ACCESSIBILITY_FONT_SCALE));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL, evt.get(MapboxEvent.ATTRIBUTE_BATTERY_LEVEL));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_PLUGGED_IN, evt.get(MapboxEvent.ATTRIBUTE_PLUGGED_IN));
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_WIFI, evt.get(MapboxEvent.ATTRIBUTE_WIFI));
-
- // Special Cases where empty string is denoting null and therefore should not be sent at all
- // This arises as thread safe Hashtable does not accept null values (nor keys)
- if (evt.containsKey(MapboxEvent.ATTRIBUTE_ORIENTATION)) {
- String orientation = (String) evt.get(MapboxEvent.ATTRIBUTE_ORIENTATION);
- if (!TextUtils.isEmpty(orientation)) {
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_ORIENTATION, orientation);
- }
- }
- if (evt.containsKey(MapboxEvent.ATTRIBUTE_CARRIER)) {
- String carrier = (String) evt.get(MapboxEvent.ATTRIBUTE_CARRIER);
- if (!TextUtils.isEmpty(carrier)) {
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_CARRIER, carrier);
- }
- }
- if (evt.containsKey(MapboxEvent.ATTRIBUTE_APPLICATION_STATE)) {
- String appState = (String) evt.get(MapboxEvent.ATTRIBUTE_APPLICATION_STATE);
- if (!TextUtils.isEmpty(appState)) {
- jsonObject.putOpt(MapboxEvent.ATTRIBUTE_APPLICATION_STATE,
- evt.get(MapboxEvent.ATTRIBUTE_APPLICATION_STATE));
- }
- }
-
- // Special Cases where null has to be passed if no value exists
- // Requires using put() instead of putOpt()
- String eventType = (String) evt.get(MapboxEvent.ATTRIBUTE_EVENT);
- if (!TextUtils.isEmpty(eventType) && eventType.equalsIgnoreCase(MapboxEvent.TYPE_MAP_CLICK)) {
- jsonObject.put(MapboxEvent.KEY_GESTURE_ID, evt.get(MapboxEvent.KEY_GESTURE_ID));
- }
- if (evt.containsKey(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE)) {
- String cellularNetworkType = (String) evt.get(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE);
- if (TextUtils.isEmpty(cellularNetworkType)) {
- jsonObject.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE, null);
- } else {
- jsonObject.put(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE,
- evt.get(MapboxEvent.ATTRIBUTE_CELLULAR_NETWORK_TYPE));
- }
- }
-
- jsonArray.put(jsonObject);
- }
-
- // Based on http://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html
- CertificatePinner.Builder certificatePinnerBuilder = new CertificatePinner.Builder();
- if (stagingEnv) {
- // Staging - Geotrust
- certificatePinnerBuilder
- .add("cloudfront-staging.tilestream.net", "sha256/3euxrJOrEZI15R4104UsiAkDqe007EPyZ6eTL/XxdAY=")
- .add("cloudfront-staging.tilestream.net", "sha256/5kJvNEMw0KjrCAu7eXY5HZdvyCS13BbA0VJG1RSP91w=")
- .add("cloudfront-staging.tilestream.net", "sha256/r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=");
- } else {
- certificatePinnerBuilder
- // Prod - Geotrust
- .add("events.mapbox.com", "sha256/BhynraKizavqoC5U26qgYuxLZst6pCu9J5stfL6RSYY=")
- .add("events.mapbox.com", "sha256/owrR9U9FWDWtrFF+myoRIu75JwU4sJwzvhCNLZoY37g=")
- .add("events.mapbox.com", "sha256/SQVGZiOrQXi+kqxcvWWE96HhfydlLVqFr4lQTqI5qqo=")
- // Prod - DigiCert
- .add("events.mapbox.com", "sha256/Tb0uHZ/KQjWh8N9+CZFLc4zx36LONQ55l6laDi1qtT4=")
- .add("events.mapbox.com", "sha256/RRM1dGqnDFsCJXBTHky16vi1obOlCgFFn/yOhI/y+ho=")
- .add("events.mapbox.com", "sha256/WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=");
- }
-
- OkHttpClient client = new OkHttpClient.Builder()
- .certificatePinner(certificatePinnerBuilder.build())
- .addInterceptor(new GzipRequestInterceptor())
- .build();
- RequestBody body = RequestBody.create(JSON, jsonArray.toString());
-
- String url = eventsURL + "/events/v2?access_token=" + accessToken;
-
- Request request = new Request.Builder()
- .url(url)
- .header("User-Agent", userAgent)
- .post(body)
- .build();
- response = client.newCall(request).execute();
- //Timber.d("response code = " + response.code() + " for events " + events.size());
-
- } catch (Exception exception) {
- Timber.e("FlushTheEventsTask borked: ", exception);
- } finally {
- if (response != null && response.body() != null) {
- response.body().close();
- }
- // Reset Events
- // ============
- events.removeAllElements();
- }
-
- return null;
- }
-
- }
-
-
- /**
- * TimerTask responsible for sending event data to server
- */
- private class FlushEventsTimerTask extends TimerTask {
- /**
- * The task to run should be specified in the implementation of the {@code run()}
- * method.
- */
- @Override
- public void run() {
- new FlushTheEventsTask().execute();
- }
- }
-
- private String getApplicationIdentifier() {
- try {
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
- return String.format(MapboxConstants.MAPBOX_LOCALE, "%s/%s/%s", context.getPackageName(),
- packageInfo.versionName, packageInfo.versionCode);
- } catch (Exception exception) {
- return "";
- }
- }
-
- static class ExponentialBackoffCounter {
-
- private static final long BASE_TIME = 30000 /*30 seconds*/;
- private int attempt;
-
- long getNextCount() {
- attempt++;
- return attempt * BASE_TIME;
- }
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
deleted file mode 100644
index 2274fb2b82..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryLocationReceiver.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.location.Location;
-import android.location.LocationManager;
-
-/**
- * Listener for Location updates generated by implementing app.
- */
-public class TelemetryLocationReceiver extends BroadcastReceiver {
-
- public static final String INTENT_STRING = "com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver";
-
- /**
- * Default Constructor
- */
- public TelemetryLocationReceiver() {
- super();
- }
-
- /**
- * This method is called when the BroadcastReceiver is receiving an Intent
- * broadcast. During this time you can use the other methods on
- * BroadcastReceiver to view/modify the current result values. This method
- * is always called within the main thread of its process, unless you
- * explicitly asked for it to be scheduled on a different thread using
- * {@link Context#registerReceiver(BroadcastReceiver,
- * android.content.IntentFilter, String, android.os.Handler)}. When it runs on the main
- * thread you should
- * never perform long-running operations in it (there is a timeout of
- * 10 seconds that the system allows before considering the receiver to
- * be blocked and a candidate to be killed). You cannot launch a popup dialog
- * in your implementation of onReceive().
- * <p>
- * <p><b>If this BroadcastReceiver was launched through a &lt;receiver&gt; tag,
- * then the object is no longer alive after returning from this
- * function.</b> This means you should not perform any operations that
- * return a result to you asynchronously -- in particular, for interacting
- * with services, you should use
- * {@link Context#startService(Intent)} instead of
- * {@link Context#bindService(Intent, android.content.ServiceConnection, int)}. If you wish
- * to interact with a service that is already running, you can use
- * {@link #peekService}.
- * <p>
- * <p>The Intent filters used in {@link Context#registerReceiver}
- * and in application manifests are <em>not</em> guaranteed to be exclusive. They
- * are hints to the operating system about how to find suitable recipients. It is
- * possible for senders to force delivery to specific recipients, bypassing filter
- * resolution. For this reason, {@link #onReceive(Context, Intent) onReceive()}
- * implementations should respond only to known actions, ignoring any unexpected
- * Intents that they may receive.
- *
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null || intent.getExtras() == null) {
- // see https://github.com/mapbox/mapbox-gl-native/issues/6934
- return;
- }
-
- Location location = (Location) intent.getExtras().get(LocationManager.KEY_LOCATION_CHANGED);
- if (location != null) {
- MapboxEventManager.getMapboxEventManager().addLocationEvent(location);
- }
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
deleted file mode 100644
index c667c1199d..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryService.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ServiceInfo;
-import android.os.AsyncTask;
-import android.os.IBinder;
-import android.support.annotation.Nullable;
-import android.support.v4.content.LocalBroadcastManager;
-
-import timber.log.Timber;
-
-/**
- * Manages Startup and Shutdown of Telemetry resources
- */
-public class TelemetryService extends Service {
-
- private TelemetryLocationReceiver telemetryLocationReceiver = null;
-
- /**
- * Return the communication channel to the service. May return null if
- * clients can not bind to the service. The returned
- * {@link IBinder} is usually for a complex interface
- * that has been <a href="{@docRoot}guide/components/aidl.html">described using
- * aidl</a>.
- * <p>
- * <p><em>Note that unlike other application components, calls on to the
- * IBinder interface returned here may not happen on the main thread
- * of the process</em>. More information about the main thread can be found in
- * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
- * Threads</a>.</p>
- *
- * @param intent The Intent that was used to bind to this service,
- * as given to {@link Context#bindService
- * Context.bindService}. Note that any extras that were included with
- * the Intent at that point will <em>not</em> be seen here.
- * @return Return an IBinder through which clients can call on to the
- * service.
- */
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
-
- /**
- * Called by the system when the service is first created. Do not call this method directly.
- */
- @Override
- public void onCreate() {
- super.onCreate();
-
- Timber.i("onCreate() called");
-
- // Enable Location Listening for lifecycle of app
- LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(
- new TelemetryLocationReceiver(),
- new IntentFilter(TelemetryLocationReceiver.INTENT_STRING)
- );
- }
-
- /**
- * Called by the system to notify a Service that it is no longer used and is being removed. The
- * service should clean up any resources it holds (threads, registered
- * receivers, etc) at this point. Upon return, there will be no more calls
- * in to this Service object and it is effectively dead. Do not call this method directly.
- */
- @Override
- public void onDestroy() {
- shutdownTelemetry();
- super.onDestroy();
- }
-
- /**
- * This is called if the service is currently running and the user has
- * removed a task that comes from the service's application. If you have
- * set {@link ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
- * then you will not receive this callback; instead, the service will simply
- * be stopped.
- *
- * @param rootIntent The original root Intent that was used to launch
- * the task that is being removed.
- */
- @Override
- public void onTaskRemoved(Intent rootIntent) {
- shutdownTelemetry();
- super.onTaskRemoved(rootIntent);
- }
-
- /**
- * Called by the system every time a client explicitly starts the service by calling
- * {@link Context#startService}, providing the arguments it supplied and a
- * unique integer token representing the start request. Do not call this method directly.
- * <p>
- * <p>For backwards compatibility, the default implementation calls
- * {@link #onStart} and returns either {@link #START_STICKY}
- * or {@link #START_STICKY_COMPATIBILITY}.
- * </p>
- * <p>If you need your application to run on platform versions prior to API
- * level 5, you can use the following model to handle the older {@link #onStart}
- * callback in that case. The <code>handleCommand</code> method is implemented by
- * you as appropriate:
- * </p>
- * <p>
- * <p class="caution">Note that the system calls this on your
- * service's main thread. A service's main thread is the same
- * thread where UI operations take place for Activities running in the
- * same process. You should always avoid stalling the main
- * thread's event loop. When doing long-running operations,
- * network calls, or heavy disk I/O, you should kick off a new
- * thread, or use {@link AsyncTask}.</p>
- *
- * @param intent The Intent supplied to {@link Context#startService},
- * as given. This may be null if the service is being restarted after
- * its process has gone away, and it had previously returned anything
- * except {@link #START_STICKY_COMPATIBILITY}.
- * @param flags Additional data about this start request. Currently either
- * 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
- * @param startId A unique integer representing this specific request to
- * start. Use with {@link #stopSelfResult(int)}.
- * @return The return value indicates what semantics the system should
- * use for the service's current started state. It may be one of the
- * constants associated with the {@link #START_CONTINUATION_MASK} bits.
- * @see #stopSelfResult(int)
- */
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
- Timber.i("onStartCommand() called");
-
- return START_NOT_STICKY;
- }
-
- private void shutdownTelemetry() {
-
- // Send Any Remaining events to the server
- MapboxEventManager.getMapboxEventManager().flushEventsQueueImmediately();
-
- // Undesired, but needed trick to keep app alive long enough for data to get to server
- try {
- Thread.sleep(1000);
- } catch (Exception exception) {
- Timber.e("Error while trying to sleep for 1 second: " + exception);
- }
-
- try {
- unregisterReceiver(telemetryLocationReceiver);
- } catch (IllegalArgumentException illegalArgumentException) {
- Timber.e("Error when unregisterReceiver: " + illegalArgumentException);
- }
-
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java
deleted file mode 100644
index 725cf016be..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/telemetry/package-info.java
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Contains the Mapbox Maps Android Telemetry API classes.
- */
-package com.mapbox.mapboxsdk.telemetry;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index d45d647247..2da2472d69 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -119,4 +119,4 @@ public class ColorUtils {
throw new ConversionException("Not a valid rgb/rgba value");
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
deleted file mode 100644
index 30ec214798..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MathUtils.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.mapbox.mapboxsdk.utils;
-
-public class MathUtils {
-
- /**
- * Test a value in specified range, returning minimum if it's below, and maximum if it's above
- *
- * @param value Value to test
- * @param min Minimum value of range
- * @param max Maximum value of range
- * @return value if it's between min and max, min if it's below, max if it's above
- */
- public static double clamp(double value, double min, double max) {
- return Math.max(min, Math.min(max, value));
- }
-
- /**
- * Test a value in specified range, returning minimum if it's below, and maximum if it's above
- *
- * @param value Value to test
- * @param min Minimum value of range
- * @param max Maximum value of range
- * @return value if it's between min and max, min if it's below, max if it's above
- */
- public static float clamp(float value, float min, float max) {
- return Math.max(min, Math.min(max, value));
- }
-
- /**
- * Constrains value to the given range (including min, excluding max) via modular arithmetic.
- * <p>
- * Same formula as used in Core GL (wrap.hpp)
- * std::fmod((std::fmod((value - min), d) + d), d) + min;
- *
- * @param value Value to wrap
- * @param min Minimum value
- * @param max Maximum value
- * @return Wrapped value
- */
- public static double wrap(double value, double min, double max) {
- double delta = max - min;
-
- double firstMod = (value - min) % delta;
- double secondMod = (firstMod + delta) % delta;
-
- return secondMod + min;
- }
-
- /**
- * Convert bearing from core to match Android SDK value.
- *
- * @param nativeBearing bearing value coming from core
- * @return bearing in degrees starting from 0 rotating clockwise
- */
- public static double convertNativeBearing(double nativeBearing) {
- double direction = -nativeBearing;
-
- while (direction > 360) {
- direction -= 360;
- }
- while (direction < 0) {
- direction += 360;
- }
- return direction;
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
index 5b2945d55d..e786aaca4c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
@@ -8,20 +8,31 @@
<public name="mapbox_AlertDialogStyle" type="style" />
<!-- Exposed attrs.xml -->
- <public name="mapbox_accessToken" type="attr" />
+ <!--Configuration-->
<public name="mapbox_styleUrl" type="attr" />
<public name="mapbox_apiBaseUrl" type="attr" />
+ <!--Camera-->
<public name="mapbox_cameraTargetLng" type="attr" />
<public name="mapbox_cameraTargetLat" type="attr" />
<public name="mapbox_cameraZoom_level" type="attr" />
<public name="mapbox_cameraBearing" type="attr" />
+ <public name="mapbox_cameraTilt" type="attr" />
+ <!--Zoom-->
+ <public name="mapbox_cameraZoomMax" ftype="attr" />
+ <public name="mapbox_cameraZoomMin" type="attr" />
+
+ <!--Gestures-->
<public name="mapbox_uiZoomGestures" type="attr" />
<public name="mapbox_uiScrollGestures" type="attr" />
<public name="mapbox_uiRotateGestures" type="attr" />
+ <public name="mapbox_uiTiltGestures" type="attr" />
+
+ <!--UI-Controls-->
<public name="mapbox_uiZoomControls" type="attr" />
+ <!--MyLocation-->
<public name="mapbox_myLocation" type="attr" />
<public name="mapbox_myLocationTintColor" type="attr" />
<public name="mapbox_myLocationDrawable" type="attr" />
@@ -35,6 +46,7 @@
<public name="mapbox_myLocationAccuracyTintColor" type="attr" />
<public name="mapbox_myLocationAccuracyAlpha" type="attr" />
+ <!--Compass-->
<public name="mapbox_uiCompass" type="attr" />
<public name="mapbox_uiCompassGravity" type="attr" />
<public name="mapbox_uiCompassMarginLeft" type="attr" />
@@ -43,6 +55,7 @@
<public name="mapbox_uiCompassMarginBottom" type="attr" />
<public name="mapbox_uiCompassFadeFacingNorth" type="attr" />
+ <!--Logo-->
<public name="mapbox_uiLogo" type="attr" />
<public name="mapbox_uiLogoGravity" type="attr" />
<public name="mapbox_uiLogoMarginLeft" type="attr" />
@@ -50,6 +63,7 @@
<public name="mapbox_uiLogoMarginRight" type="attr" />
<public name="mapbox_uiLogoMarginBottom" type="attr" />
+ <!--Attribution-->
<public name="mapbox_uiAttribution" type="attr" />
<public name="mapbox_uiAttributionGravity" type="attr" />
<public name="mapbox_uiAttributionMarginLeft" type="attr" />
@@ -57,6 +71,7 @@
<public name="mapbox_uiAttributionMarginRight" type="attr" />
<public name="mapbox_uiAttributionMarginBottom" type="attr" />
+ <!-- Deprecated to use TextureView-->
<public name="mapbox_renderTextureMode" type="attr" />
<!-- Exposed styles -->
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml
index 64d7f46c2d..4c733ed112 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml
@@ -2,4 +2,4 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimaryDark" android:state_pressed="true" />
<item android:color="?attr/colorPrimary" />
-</selector> \ No newline at end of file
+</selector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml
index ef82c18f5d..2fd6815c23 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml
@@ -6,4 +6,4 @@
<solid android:color="@android:color/white" />
</shape>
</item>
-</ripple> \ No newline at end of file
+</ripple>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml
index 45073bb1f3..3efe48615b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml
@@ -3,4 +3,4 @@
<item android:drawable="@color/mapbox_gray_light" android:state_pressed="true" />
<item android:drawable="@color/mapbox_gray_light" android:state_focused="true" />
<item android:drawable="@android:color/transparent" />
-</selector> \ No newline at end of file
+</selector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml
index 3ead19b781..01fc7cc2e8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_info_bg_selector.xml
@@ -2,4 +2,4 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/mapbox_info_icon_selected" android:state_pressed="true" />
<item android:drawable="@drawable/mapbox_info_icon_default" />
-</selector> \ No newline at end of file
+</selector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml
index df0687bbd3..21054aabcb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_mylocation_bg_shape.xml
@@ -7,4 +7,4 @@
<size
android:width="@dimen/mapbox_my_locationview_outer_circle"
android:height="@dimen/mapbox_my_locationview_outer_circle" />
-</shape> \ No newline at end of file
+</shape>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_popup_window_transparent.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_popup_window_transparent.xml
new file mode 100644
index 0000000000..87338de33e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_popup_window_transparent.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#00000000"/>
+ <stroke
+ android:width="0dp"
+ android:color="#00000000"/>
+ <padding
+ android:bottom="0dp"
+ android:left="0dp"
+ android:right="0dp"
+ android:top="0dp"/>
+</shape> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
index e1673902ef..e4f01cb40f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
@@ -1,56 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
+<com.mapbox.mapboxsdk.annotations.BubbleLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="16dp"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:paddingTop="14dp"
+ app:mapbox_bl_arrowDirection="bottom"
+ app:mapbox_bl_arrowHeight="8dp"
+ app:mapbox_bl_arrowPosition="16dp"
+ app:mapbox_bl_arrowWidth="8dp"
+ app:mapbox_bl_bubbleColor="@android:color/white"
+ app:mapbox_bl_cornersRadius="6dp"
+ app:mapbox_bl_strokeColor="@android:color/darker_gray"
+ app:mapbox_bl_strokeWidth="1dp">
- <LinearLayout
- android:id="@+id/infowindow_content"
+ <TextView
+ android:id="@+id/infowindow_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@drawable/mapbox_infowindow_icon_bg"
- android:orientation="vertical"
- android:paddingBottom="16dp"
- android:paddingLeft="20dp"
- android:paddingRight="20dp"
- android:paddingTop="14dp">
+ android:layout_marginBottom="2dp"
+ android:maxEms="17"
+ android:text="@string/mapbox_infoWindowTitle"
+ android:textColor="@android:color/black"
+ android:textSize="18sp"
+ android:textStyle="bold"/>
- <TextView
- android:id="@+id/infowindow_title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="2dp"
- android:maxEms="17"
- android:text="@string/mapbox_infoWindowTitle"
- android:textColor="@android:color/black"
- android:textSize="18sp"
- android:textStyle="bold" />
-
- <TextView
- android:id="@+id/infowindow_description"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginBottom="2dp"
- android:layout_marginTop="2dp"
- android:lineSpacingExtra="1dp"
- android:maxEms="17"
- android:text="@string/mapbox_infoWindowDescription"
- android:textColor="@color/mapbox_gray"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/infowindow_subdescription"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxEms="17"
- android:text="@string/mapbox_infoWindowAddress"
- android:textColor="@android:color/black"
- android:textSize="12sp"
- android:visibility="gone" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/infowindow_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="2dp"
+ android:layout_marginTop="2dp"
+ android:lineSpacingExtra="1dp"
+ android:maxEms="17"
+ android:text="@string/mapbox_infoWindowDescription"
+ android:textColor="@color/mapbox_gray"
+ android:textSize="14sp"/>
- <com.mapbox.mapboxsdk.annotations.InfoWindowTipView
- android:id="@+id/infowindow_tipview"
- android:layout_width="@dimen/mapbox_infowindow_tipview_width"
- android:layout_height="14dp"
- android:layout_below="@+id/infowindow_content" />
+ <TextView
+ android:id="@+id/infowindow_subdescription"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxEms="17"
+ android:text="@string/mapbox_infoWindowAddress"
+ android:textColor="@android:color/black"
+ android:textSize="12sp"
+ android:visibility="gone"/>
-</merge>
+</com.mapbox.mapboxsdk.annotations.BubbleLayout>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_view.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_view.xml
deleted file mode 100644
index ff47642426..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_view.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.mapbox.mapboxsdk.annotations.InfoWindowView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
index c6dcd35a2f..9810e8900b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
@@ -41,4 +41,4 @@
android:padding="7dp"
android:src="@drawable/mapbox_info_bg_selector" />
-</merge> \ No newline at end of file
+</merge>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
index 5517c0cfe6..d87f443586 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
@@ -38,4 +38,4 @@
android:layout_margin="10dp"
android:src="@drawable/mapbox_compass_icon" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index 12c395d46f..738cae07be 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -3,116 +3,134 @@
<declare-styleable name="mapbox_MapView">
<!--Configuration-->
- <attr name="mapbox_styleUrl" format="string" />
- <attr name="mapbox_apiBaseUrl" format="string" />
+ <attr name="mapbox_styleUrl" format="string"/>
+ <attr name="mapbox_apiBaseUrl" format="string"/>
<!--Camera-->
- <attr name="mapbox_cameraTargetLat" format="float" />
- <attr name="mapbox_cameraTargetLng" format="float" />
- <attr name="mapbox_cameraZoom" format="float" />
- <attr name="mapbox_cameraBearing" format="float" />
- <attr name="mapbox_cameraTilt" format="float" />
+ <attr name="mapbox_cameraTargetLat" format="float"/>
+ <attr name="mapbox_cameraTargetLng" format="float"/>
+ <attr name="mapbox_cameraZoom" format="float"/>
+ <attr name="mapbox_cameraBearing" format="float"/>
+ <attr name="mapbox_cameraTilt" format="float"/>
<!--Zoom-->
- <attr name="mapbox_cameraZoomMax" format="float" />
- <attr name="mapbox_cameraZoomMin" format="float" />
+ <attr name="mapbox_cameraZoomMax" format="float"/>
+ <attr name="mapbox_cameraZoomMin" format="float"/>
<!--Gestures-->
- <attr name="mapbox_uiZoomGestures" format="boolean" />
- <attr name="mapbox_uiScrollGestures" format="boolean" />
- <attr name="mapbox_uiRotateGestures" format="boolean" />
- <attr name="mapbox_uiTiltGestures" format="boolean" />
+ <attr name="mapbox_uiZoomGestures" format="boolean"/>
+ <attr name="mapbox_uiScrollGestures" format="boolean"/>
+ <attr name="mapbox_uiRotateGestures" format="boolean"/>
+ <attr name="mapbox_uiTiltGestures" format="boolean"/>
+ <attr name="mapbox_uiDoubleTapGestures" format="boolean"/>
<!--UI-Controls-->
- <attr name="mapbox_uiZoomControls" format="boolean" />
+ <attr name="mapbox_uiZoomControls" format="boolean"/>
<!--MyLocation-->
- <attr name="mapbox_myLocation" format="boolean" />
- <attr name="mapbox_myLocationTintColor" format="color" />
- <attr name="mapbox_myLocationDrawable" format="reference" />
- <attr name="mapbox_myLocationBearingDrawable" format="reference" />
- <attr name="mapbox_myLocationBackgroundDrawable" format="reference" />
- <attr name="mapbox_myLocationBackgroundTintColor" format="color" />
- <attr name="mapbox_myLocationBackgroundMarginLeft" format="dimension" />
- <attr name="mapbox_myLocationBackgroundMarginTop" format="dimension" />
- <attr name="mapbox_myLocationBackgroundMarginRight" format="dimension" />
- <attr name="mapbox_myLocationBackgroundMarginBottom" format="dimension" />
- <attr name="mapbox_myLocationAccuracyTintColor" format="color" />
- <attr name="mapbox_myLocationAccuracyAlpha" format="integer" />
+ <attr name="mapbox_myLocation" format="boolean"/>
+ <attr name="mapbox_myLocationTintColor" format="color"/>
+ <attr name="mapbox_myLocationDrawable" format="reference"/>
+ <attr name="mapbox_myLocationBearingDrawable" format="reference"/>
+ <attr name="mapbox_myLocationBackgroundDrawable" format="reference"/>
+ <attr name="mapbox_myLocationBackgroundTintColor" format="color"/>
+ <attr name="mapbox_myLocationBackgroundMarginLeft" format="dimension"/>
+ <attr name="mapbox_myLocationBackgroundMarginTop" format="dimension"/>
+ <attr name="mapbox_myLocationBackgroundMarginRight" format="dimension"/>
+ <attr name="mapbox_myLocationBackgroundMarginBottom" format="dimension"/>
+ <attr name="mapbox_myLocationAccuracyTintColor" format="color"/>
+ <attr name="mapbox_myLocationAccuracyAlpha" format="integer"/>
<!--Compass-->
- <attr name="mapbox_uiCompass" format="boolean" />
+ <attr name="mapbox_uiCompass" format="boolean"/>
<attr name="mapbox_uiCompassGravity">
- <flag name="top" value="0x30" />
- <flag name="bottom" value="0x50" />
- <flag name="left" value="0x03" />
- <flag name="right" value="0x05" />
- <flag name="center_vertical" value="0x10" />
- <flag name="fill_vertical" value="0x70" />
- <flag name="center_horizontal" value="0x01" />
- <flag name="fill_horizontal" value="0x07" />
- <flag name="center" value="0x11" />
- <flag name="fill" value="0x77" />
- <flag name="clip_vertical" value="0x80" />
- <flag name="clip_horizontal" value="0x08" />
- <flag name="start" value="0x00800003" />
- <flag name="end" value="0x00800005" />
+ <flag name="top" value="0x30"/>
+ <flag name="bottom" value="0x50"/>
+ <flag name="left" value="0x03"/>
+ <flag name="right" value="0x05"/>
+ <flag name="center_vertical" value="0x10"/>
+ <flag name="fill_vertical" value="0x70"/>
+ <flag name="center_horizontal" value="0x01"/>
+ <flag name="fill_horizontal" value="0x07"/>
+ <flag name="center" value="0x11"/>
+ <flag name="fill" value="0x77"/>
+ <flag name="clip_vertical" value="0x80"/>
+ <flag name="clip_horizontal" value="0x08"/>
+ <flag name="start" value="0x00800003"/>
+ <flag name="end" value="0x00800005"/>
</attr>
- <attr name="mapbox_uiCompassMarginLeft" format="dimension" />
- <attr name="mapbox_uiCompassMarginTop" format="dimension" />
- <attr name="mapbox_uiCompassMarginRight" format="dimension" />
- <attr name="mapbox_uiCompassMarginBottom" format="dimension" />
- <attr name="mapbox_uiCompassFadeFacingNorth" format="boolean" />
+ <attr name="mapbox_uiCompassMarginLeft" format="dimension"/>
+ <attr name="mapbox_uiCompassMarginTop" format="dimension"/>
+ <attr name="mapbox_uiCompassMarginRight" format="dimension"/>
+ <attr name="mapbox_uiCompassMarginBottom" format="dimension"/>
+ <attr name="mapbox_uiCompassFadeFacingNorth" format="boolean"/>
<!--Logo-->
- <attr name="mapbox_uiLogo" format="boolean" />
+ <attr name="mapbox_uiLogo" format="boolean"/>
<attr name="mapbox_uiLogoGravity">
- <flag name="top" value="0x30" />
- <flag name="bottom" value="0x50" />
- <flag name="left" value="0x03" />
- <flag name="right" value="0x05" />
- <flag name="center_vertical" value="0x10" />
- <flag name="fill_vertical" value="0x70" />
- <flag name="center_horizontal" value="0x01" />
- <flag name="fill_horizontal" value="0x07" />
- <flag name="center" value="0x11" />
- <flag name="fill" value="0x77" />
- <flag name="clip_vertical" value="0x80" />
- <flag name="clip_horizontal" value="0x08" />
- <flag name="start" value="0x00800003" />
- <flag name="end" value="0x00800005" />
+ <flag name="top" value="0x30"/>
+ <flag name="bottom" value="0x50"/>
+ <flag name="left" value="0x03"/>
+ <flag name="right" value="0x05"/>
+ <flag name="center_vertical" value="0x10"/>
+ <flag name="fill_vertical" value="0x70"/>
+ <flag name="center_horizontal" value="0x01"/>
+ <flag name="fill_horizontal" value="0x07"/>
+ <flag name="center" value="0x11"/>
+ <flag name="fill" value="0x77"/>
+ <flag name="clip_vertical" value="0x80"/>
+ <flag name="clip_horizontal" value="0x08"/>
+ <flag name="start" value="0x00800003"/>
+ <flag name="end" value="0x00800005"/>
</attr>
- <attr name="mapbox_uiLogoMarginLeft" format="dimension" />
- <attr name="mapbox_uiLogoMarginTop" format="dimension" />
- <attr name="mapbox_uiLogoMarginRight" format="dimension" />
- <attr name="mapbox_uiLogoMarginBottom" format="dimension" />
+ <attr name="mapbox_uiLogoMarginLeft" format="dimension"/>
+ <attr name="mapbox_uiLogoMarginTop" format="dimension"/>
+ <attr name="mapbox_uiLogoMarginRight" format="dimension"/>
+ <attr name="mapbox_uiLogoMarginBottom" format="dimension"/>
<!--Attribution-->
- <attr name="mapbox_uiAttribution" format="boolean" />
+ <attr name="mapbox_uiAttribution" format="boolean"/>
<attr name="mapbox_uiAttributionGravity">
- <flag name="top" value="0x30" />
- <flag name="bottom" value="0x50" />
- <flag name="left" value="0x03" />
- <flag name="right" value="0x05" />
- <flag name="center_vertical" value="0x10" />
- <flag name="fill_vertical" value="0x70" />
- <flag name="center_horizontal" value="0x01" />
- <flag name="fill_horizontal" value="0x07" />
- <flag name="center" value="0x11" />
- <flag name="fill" value="0x77" />
- <flag name="clip_vertical" value="0x80" />
- <flag name="clip_horizontal" value="0x08" />
- <flag name="start" value="0x00800003" />
- <flag name="end" value="0x00800005" />
+ <flag name="top" value="0x30"/>
+ <flag name="bottom" value="0x50"/>
+ <flag name="left" value="0x03"/>
+ <flag name="right" value="0x05"/>
+ <flag name="center_vertical" value="0x10"/>
+ <flag name="fill_vertical" value="0x70"/>
+ <flag name="center_horizontal" value="0x01"/>
+ <flag name="fill_horizontal" value="0x07"/>
+ <flag name="center" value="0x11"/>
+ <flag name="fill" value="0x77"/>
+ <flag name="clip_vertical" value="0x80"/>
+ <flag name="clip_horizontal" value="0x08"/>
+ <flag name="start" value="0x00800003"/>
+ <flag name="end" value="0x00800005"/>
</attr>
- <attr name="mapbox_uiAttributionMarginLeft" format="dimension" />
- <attr name="mapbox_uiAttributionMarginTop" format="dimension" />
- <attr name="mapbox_uiAttributionMarginRight" format="dimension" />
- <attr name="mapbox_uiAttributionMarginBottom" format="dimension" />
- <attr name="mapbox_uiAttributionTintColor" format="color" />
+ <attr name="mapbox_uiAttributionMarginLeft" format="dimension"/>
+ <attr name="mapbox_uiAttributionMarginTop" format="dimension"/>
+ <attr name="mapbox_uiAttributionMarginRight" format="dimension"/>
+ <attr name="mapbox_uiAttributionMarginBottom" format="dimension"/>
+ <attr name="mapbox_uiAttributionTintColor" format="color"/>
<!-- Deprecated to use TextureView-->
- <attr name="mapbox_renderTextureMode" format="boolean" />
+ <attr name="mapbox_renderTextureMode" format="boolean"/>
</declare-styleable>
+
+ <declare-styleable name="mapbox_BubbleLayout">
+ <attr name="mapbox_bl_arrowWidth" format="dimension|reference"/>
+ <attr name="mapbox_bl_cornersRadius" format="dimension|reference"/>
+ <attr name="mapbox_bl_arrowHeight" format="dimension|reference"/>
+ <attr name="mapbox_bl_arrowPosition" format="dimension|reference"/>
+ <attr name="mapbox_bl_bubbleColor" format="color|reference"/>
+ <attr name="mapbox_bl_strokeWidth" format="dimension|reference"/>
+ <attr name="mapbox_bl_strokeColor" format="color|reference"/>
+
+ <attr name="mapbox_bl_arrowDirection" format="enum">
+ <enum name="left" value="0"/>
+ <enum name="right" value="1"/>
+ <enum name="top" value="2"/>
+ <enum name="bottom" value="3"/>
+ </attr>
+ </declare-styleable>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index 31b9dd2bcd..df6983e11d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <dimen name="mapbox_infowindow_tipview_width">20dp</dimen>
+ <dimen name="mapbox_infowindow_tipview_width">8dp</dimen>
<dimen name="mapbox_infowindow_margin">8dp</dimen>
<dimen name="mapbox_infowindow_offset">-2dp</dimen>
<dimen name="mapbox_infowindow_line_width">1.5dp</dimen>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
index 82d9d1e076..eba1fb3a7d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
@@ -3,4 +3,4 @@
<style name="mapbox_AlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert"/>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 318f891127..1b4d54106d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -1,22 +1,15 @@
apply plugin: 'com.android.application'
-ext {
- supportLibVersion = '25.1.0'
- espressoVersion = '2.2.2'
- testRunnerVersion = '0.5'
- leakCanaryVersion = '1.5'
-}
-
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.mapbox.mapboxsdk.testapp"
- minSdkVersion 15
- targetSdkVersion 25
- versionCode 11
- versionName "5.0.0"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode rootProject.ext.versionCode
+ versionName rootProject.ext.versionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
@@ -61,31 +54,31 @@ dependencies {
}
// Support libraries
- compile "com.android.support:support-annotations:${supportLibVersion}"
- compile "com.android.support:support-v4:${supportLibVersion}"
- compile "com.android.support:appcompat-v7:${supportLibVersion}"
- compile "com.android.support:design:${supportLibVersion}"
- compile "com.android.support:recyclerview-v7:${supportLibVersion}"
+ compile rootProject.ext.dep.supportAnnotations
+ compile rootProject.ext.dep.supportV4
+ compile rootProject.ext.dep.supportAppcompatV7
+ compile rootProject.ext.dep.supportDesign
+ compile rootProject.ext.dep.supportRecyclerView
// Leak Canary
- debugCompile "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
- releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
- testCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
+ debugCompile rootProject.ext.dep.leakCanaryDebug
+ releaseCompile rootProject.ext.dep.leakCanaryRelease
+ testCompile rootProject.ext.dep.leakCanaryTest
// Mapbox Android Services (Java component)
- compile('com.mapbox.mapboxsdk:mapbox-java-services:2.0.0-SNAPSHOT@jar') {
+ compile(rootProject.ext.dep.mapboxJavaServices) {
transitive = true
}
// Testing dependencies
- testCompile 'junit:junit:4.12'
- testCompile 'org.mockito:mockito-core:2.2.27'
- androidTestCompile 'com.squareup.spoon:spoon-client:1.6.2'
- androidTestCompile "com.android.support:support-annotations:${supportLibVersion}"
- androidTestCompile "com.android.support.test:runner:${testRunnerVersion}"
- androidTestCompile "com.android.support.test:rules:${testRunnerVersion}"
- androidTestCompile "com.android.support.test.espresso:espresso-core:${espressoVersion}"
- androidTestCompile "com.android.support.test.espresso:espresso-intents:${espressoVersion}"
+ testCompile rootProject.ext.dep.junit
+ testCompile rootProject.ext.dep.mockito
+ androidTestCompile rootProject.ext.dep.testSpoonRunner
+ androidTestCompile rootProject.ext.dep.supportAnnotations
+ androidTestCompile rootProject.ext.dep.testRunner
+ androidTestCompile rootProject.ext.dep.testRules
+ androidTestCompile rootProject.ext.dep.testEspressoCore
+ androidTestCompile rootProject.ext.dep.testEspressoIntents
}
apply from: 'gradle-make.gradle'
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle
index cdcc7f1e23..fdc4399f16 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle
@@ -12,6 +12,7 @@ task checkstyle(type: Checkstyle) {
source 'src'
include '**/*.java'
exclude '**/gen/**'
+ exclude '**/style/*LayerTest.java'
classpath = files()
ignoreFailures = false
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
index 21da83c4a0..1068e5e69e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
@@ -3,7 +3,7 @@
//
task accessToken {
- def tokenFile = new File("MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml")
+ def tokenFile = new File("${projectDir}/src/main/res/values/developer-config.xml")
if (!tokenFile.exists()) {
String tokenFileContents = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<resources>\n" +
@@ -19,4 +19,4 @@ task accessToken {
gradle.projectsEvaluated {
preBuild.dependsOn('accessToken')
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle
index f455e263c0..5cb5d75bbb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-device-farm.gradle
@@ -40,4 +40,4 @@ devicefarm {
instrumentation {
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-make.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-make.gradle
index 29567df6f0..65d971cc96 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-make.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-make.gradle
@@ -15,4 +15,4 @@ task makeAndroid(type: Exec) {
task makeAndroidAll(type: Exec) {
workingDir '../../'
commandLine 'make', 'apackage'
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle
index 1c9afaeb7c..7a5b966443 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-spoon.gradle
@@ -5,4 +5,4 @@ spoon {
// for more options see https://github.com/stanfy/spoon-gradle-plugin
grantAllPermissions = true
debug = true
-} \ No newline at end of file
+}
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 330de1e9c8..2cd077f510 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
@@ -107,6 +107,7 @@ public class MapboxMapTest {
}
@Test
+ @Ignore
public void testInitialZoomLevels() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = activity.getMapboxMap();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
index 5ead54eb7b..d4b0dbad72 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -44,6 +45,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToCameraPositionTarget() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -66,6 +68,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToCameraPositionTargetZoom() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -114,6 +117,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToBounds() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -142,6 +146,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToMoveBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -161,6 +166,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToZoomIn() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -175,6 +181,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToZoomOut() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -190,6 +197,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToZoomBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -205,6 +213,7 @@ public class CameraAnimateTest {
}
@Test
+ @Ignore
public void testAnimateToZoomTo() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
index 22af72cebb..83e7d6084c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -44,6 +45,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToCameraPositionTarget() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -66,6 +68,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToCameraPositionTargetZoom() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -84,6 +87,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToCameraPosition() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -114,6 +118,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToBounds() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -142,6 +147,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToMoveBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -161,6 +167,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToZoomIn() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -175,6 +182,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToZoomOut() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -189,6 +197,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToZoomBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -204,6 +213,7 @@ public class CameraEaseTest {
}
@Test
+ @Ignore
public void testEaseToZoomTo() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
index 3ca61f7e9d..2d01347d22 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java
@@ -19,6 +19,7 @@ import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -44,6 +45,7 @@ public class CameraInternalApiTest {
}
@Test
+ @Ignore
public void testBearing() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
EspressoTestActivity activity = rule.getActivity();
@@ -59,6 +61,7 @@ public class CameraInternalApiTest {
}
@Test
+ @Ignore
public void testTilt() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
EspressoTestActivity activity = rule.getActivity();
@@ -74,6 +77,7 @@ public class CameraInternalApiTest {
}
@Test
+ @Ignore
public void testLatLng() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
EspressoTestActivity activity = rule.getActivity();
@@ -166,4 +170,4 @@ public class CameraInternalApiTest {
MapViewUtils.setLatLng(mapboxMap, new LatLng(1.1, 2.2));
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
index b3a7fe0d11..becf9db7cb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
@@ -22,6 +22,7 @@ import com.mapbox.mapboxsdk.testapp.utils.ViewUtils;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
@@ -44,6 +45,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToCameraPositionTarget() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -66,6 +68,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToCameraPositionTargetZoom() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -84,6 +87,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToCameraPosition() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -114,6 +118,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToBounds() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -142,6 +147,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToMoveBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -161,6 +167,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToZoomIn() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -175,6 +182,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToZoomOut() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -190,6 +198,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToZoomBy() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
@@ -205,6 +214,7 @@ public class CameraMoveTest {
}
@Test
+ @Ignore
public void testMoveToZoomTo() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
final MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
index b4be73be7a..f49296a164 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesBoxCountTest.java
@@ -58,4 +58,4 @@ public class QueryRenderedFeaturesBoxCountTest {
Espresso.unregisterIdlingResources(idlingResource);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
index b8cd46e612..0333aba191 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesHighlightTest.java
@@ -78,4 +78,4 @@ public class QueryRenderedFeaturesHighlightTest {
},
Press.FINGER);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
index 3b86397603..01eb9c8b44 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/feature/QueryRenderedFeaturesPropertiesTest.java
@@ -75,4 +75,4 @@ public class QueryRenderedFeaturesPropertiesTest {
},
Press.FINGER);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
index ac10d11922..c8a983351b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/MyLocationViewTest.java
@@ -16,7 +16,7 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.testapp.R;
@@ -123,7 +123,7 @@ public class MyLocationViewTest {
mapboxMap.moveCamera(
CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
- .target(new LatLng(LocationServices.getLocationServices(view.getContext()).getLastLocation()))
+ .target(new LatLng(LocationSource.getLocationEngine(view.getContext()).getLastLocation()))
.build()
)
);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerStyleTest.java
deleted file mode 100644
index 68ed5cb05d..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerStyleTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.graphics.Color;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundPattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for BackgroundLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class BackgroundLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private BackgroundLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testBackgroundColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("background-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(backgroundColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getBackgroundColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testBackgroundColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("background-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(backgroundColor(Color.RED));
- assertEquals(layer.getBackgroundColorAsInt(), Color.RED);
- }
-
- @Test
- public void testBackgroundPattern() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("background-pattern");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(backgroundPattern("pedestrian-polygon"));
- assertEquals((String) layer.getBackgroundPattern().getValue(), (String) "pedestrian-polygon");
- }
-
- @Test
- public void testBackgroundOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("background-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(backgroundOpacity(0.3f));
- assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f);
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 ab53ae0487..510f477bce 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
@@ -1,12 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -18,16 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundPattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for BackgroundLayer
@@ -48,91 +55,147 @@ public class BackgroundLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
+ mapboxMap = rule.getActivity().getMapboxMap();
+
+ Timber.i("Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
}
@Test
public void testSetVisibility() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
- Timber.i("visibility");
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testBackgroundColor() {
+ public void testBackgroundColorAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
Timber.i("background-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(backgroundColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getBackgroundColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testBackgroundColorAsInt() {
+ public void testBackgroundColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("background-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ backgroundColor(
+ zoom(
+ exponential(
+ stop(2, backgroundColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getBackgroundColor());
+ assertNotNull(layer.getBackgroundColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getBackgroundColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getBackgroundColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getBackgroundColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getBackgroundColor().getFunction().getStops()).size());
+ }
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
+ @Test
+ public void testBackgroundColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("background-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(backgroundColor(Color.RED));
assertEquals(layer.getBackgroundColorAsInt(), Color.RED);
}
@Test
- public void testBackgroundPattern() {
+ public void testBackgroundPatternAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
Timber.i("background-pattern");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(backgroundPattern("pedestrian-polygon"));
assertEquals((String) layer.getBackgroundPattern().getValue(), (String) "pedestrian-polygon");
}
@Test
- public void testBackgroundOpacity() {
+ public void testBackgroundPatternAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("background-pattern");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ backgroundPattern(
+ zoom(
+ interval(
+ stop(2, backgroundPattern("pedestrian-polygon"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getBackgroundPattern());
+ assertNotNull(layer.getBackgroundPattern().getFunction());
+ assertEquals(CameraFunction.class, layer.getBackgroundPattern().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getBackgroundPattern().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getBackgroundPattern().getFunction().getStops()).size());
+ }
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
+ @Test
+ public void testBackgroundOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("background-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(backgroundOpacity(0.3f));
assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f);
}
+ @Test
+ public void testBackgroundOpacityAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("background-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ backgroundOpacity(
+ zoom(
+ exponential(
+ stop(2, backgroundOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getBackgroundOpacity());
+ assertNotNull(layer.getBackgroundOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getBackgroundOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getBackgroundOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getBackgroundOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getBackgroundOpacity().getFunction().getStops()).size());
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerStyleTest.java
deleted file mode 100644
index 58fda51f07..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerStyleTest.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.graphics.Color;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.CircleLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_PITCH_SCALE_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circlePitchScale;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for CircleLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class CircleLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private CircleLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testCircleRadius() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-radius");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleRadius(0.3f));
- assertEquals((Float) layer.getCircleRadius().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testCircleColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getCircleColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testCircleColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleColor(Color.RED));
- assertEquals(layer.getCircleColorAsInt(), Color.RED);
- }
-
- @Test
- public void testCircleBlur() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-blur");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleBlur(0.3f));
- assertEquals((Float) layer.getCircleBlur().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testCircleOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleOpacity(0.3f));
- assertEquals((Float) layer.getCircleOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testCircleTranslate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-translate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getCircleTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testCircleTranslateAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-translate-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circleTranslateAnchor(CIRCLE_TRANSLATE_ANCHOR_MAP));
- assertEquals((String) layer.getCircleTranslateAnchor().getValue(), (String) CIRCLE_TRANSLATE_ANCHOR_MAP);
- }
-
- @Test
- public void testCirclePitchScale() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("circle-pitch-scale");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(circlePitchScale(CIRCLE_PITCH_SCALE_MAP));
- assertEquals((String) layer.getCirclePitchScale().getValue(), (String) CIRCLE_PITCH_SCALE_MAP);
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 782598a0b2..c48a6f1d68 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
@@ -1,12 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -18,25 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_PITCH_SCALE_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.CIRCLE_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circlePitchScale;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for CircleLayer
@@ -57,12 +55,6 @@ public class CircleLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
mapboxMap = rule.getActivity().getMapboxMap();
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
@@ -70,284 +62,1087 @@ public class CircleLayerTest extends BaseStyleTest {
layer = new CircleLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
+ // Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
- Timber.i("visibility");
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testCircleRadius() {
+ public void testCircleRadiusAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
Timber.i("circle-radius");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleRadius(0.3f));
assertEquals((Float) layer.getCircleRadius().getValue(), (Float) 0.3f);
}
@Test
- public void testCircleColor() {
+ public void testCircleRadiusAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-radius");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleRadius(
+ zoom(
+ exponential(
+ stop(2, circleRadius(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleRadius());
+ assertNotNull(layer.getCircleRadius().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleRadius().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleRadius().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleRadius().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleRadius().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleRadiusAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-radius");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleRadius(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleRadius());
+ assertNotNull(layer.getCircleRadius().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleRadius().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleRadius().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleRadius().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleRadiusAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-radius");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleRadius(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, circleRadius(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleRadius());
+ assertNotNull(layer.getCircleRadius().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleRadius().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleRadius().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleRadius().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleRadiusAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-radius");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleRadius(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, circleRadius(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleRadius());
+ assertNotNull(layer.getCircleRadius().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleRadius().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleRadius().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleRadius().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getCircleRadius().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testCircleRadiusAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-radius");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleRadius(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, circleRadius(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleRadius());
+ assertNotNull(layer.getCircleRadius().getFunction());
+ assertEquals(CompositeFunction.class, layer.getCircleRadius().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getCircleRadius().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleRadius().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getCircleRadius().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getCircleRadius().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testCircleColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getCircleColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testCircleColorAsInt() {
+ public void testCircleColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleColor(
+ zoom(
+ exponential(
+ stop(2, circleColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleColor());
+ assertNotNull(layer.getCircleColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(circleColor(Color.RED));
- assertEquals(layer.getCircleColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ circleColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleColor());
+ assertNotNull(layer.getCircleColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleColor().getFunction().getStops().getClass());
}
@Test
- public void testCircleBlur() {
+ public void testCircleColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, circleColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleColor());
+ assertNotNull(layer.getCircleColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", circleColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleColor());
+ assertNotNull(layer.getCircleColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(circleColor(Color.RED));
+ assertEquals(layer.getCircleColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testCircleBlurAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-blur");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleBlur(0.3f));
assertEquals((Float) layer.getCircleBlur().getValue(), (Float) 0.3f);
}
@Test
- public void testCircleOpacity() {
+ public void testCircleBlurAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-blur");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleBlur(
+ zoom(
+ exponential(
+ stop(2, circleBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleBlur());
+ assertNotNull(layer.getCircleBlur().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleBlur().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleBlur().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleBlur().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleBlur().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleBlurAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleBlur(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleBlur());
+ assertNotNull(layer.getCircleBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleBlur().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleBlurAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleBlur(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, circleBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleBlur());
+ assertNotNull(layer.getCircleBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleBlurAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleBlur(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, circleBlur(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleBlur());
+ assertNotNull(layer.getCircleBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleBlur().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleBlur().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getCircleBlur().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testCircleBlurAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleBlur(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, circleBlur(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleBlur());
+ assertNotNull(layer.getCircleBlur().getFunction());
+ assertEquals(CompositeFunction.class, layer.getCircleBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getCircleBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleBlur().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getCircleBlur().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getCircleBlur().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testCircleOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleOpacity(0.3f));
assertEquals((Float) layer.getCircleOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testCircleTranslate() {
+ public void testCircleOpacityAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleOpacity(
+ zoom(
+ exponential(
+ stop(2, circleOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleOpacity());
+ assertNotNull(layer.getCircleOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleOpacity().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testCircleOpacityAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleOpacity());
+ assertNotNull(layer.getCircleOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleOpacity().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, circleOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleOpacity());
+ assertNotNull(layer.getCircleOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, circleOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleOpacity());
+ assertNotNull(layer.getCircleOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getCircleOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testCircleOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, circleOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleOpacity());
+ assertNotNull(layer.getCircleOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getCircleOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getCircleOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getCircleOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getCircleOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testCircleTranslateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-translate");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(circleTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getCircleTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(circleTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getCircleTranslate().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testCircleTranslateAnchor() {
+ public void testCircleTranslateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-translate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleTranslate(
+ zoom(
+ exponential(
+ stop(2, circleTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleTranslate());
+ assertNotNull(layer.getCircleTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleTranslate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleTranslateAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-translate-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleTranslateAnchor(CIRCLE_TRANSLATE_ANCHOR_MAP));
assertEquals((String) layer.getCircleTranslateAnchor().getValue(), (String) CIRCLE_TRANSLATE_ANCHOR_MAP);
}
@Test
- public void testCirclePitchScale() {
+ public void testCircleTranslateAnchorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-translate-anchor");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, circleTranslateAnchor(CIRCLE_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleTranslateAnchor());
+ assertNotNull(layer.getCircleTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getCircleTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getCircleTranslateAnchor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCirclePitchScaleAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-pitch-scale");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circlePitchScale(CIRCLE_PITCH_SCALE_MAP));
assertEquals((String) layer.getCirclePitchScale().getValue(), (String) CIRCLE_PITCH_SCALE_MAP);
}
@Test
- public void testCircleStrokeWidth() {
+ public void testCirclePitchScaleAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-pitch-scale");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circlePitchScale(
+ zoom(
+ interval(
+ stop(2, circlePitchScale(CIRCLE_PITCH_SCALE_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCirclePitchScale());
+ assertNotNull(layer.getCirclePitchScale().getFunction());
+ assertEquals(CameraFunction.class, layer.getCirclePitchScale().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getCirclePitchScale().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getCirclePitchScale().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleStrokeWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-stroke-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleStrokeWidth(0.3f));
assertEquals((Float) layer.getCircleStrokeWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testCircleStrokeColor() {
+ public void testCircleStrokeWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleStrokeWidth(
+ zoom(
+ exponential(
+ stop(2, circleStrokeWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeWidth());
+ assertNotNull(layer.getCircleStrokeWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleStrokeWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleStrokeWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleStrokeWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleStrokeWidthAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeWidth(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeWidth());
+ assertNotNull(layer.getCircleStrokeWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeWidth().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleStrokeWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleStrokeWidthAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeWidth(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, circleStrokeWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeWidth());
+ assertNotNull(layer.getCircleStrokeWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleStrokeWidthAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeWidth(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, circleStrokeWidth(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeWidth());
+ assertNotNull(layer.getCircleStrokeWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeWidth().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleStrokeWidth().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getCircleStrokeWidth().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testCircleStrokeWidthAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeWidth(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, circleStrokeWidth(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeWidth());
+ assertNotNull(layer.getCircleStrokeWidth().getFunction());
+ assertEquals(CompositeFunction.class, layer.getCircleStrokeWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getCircleStrokeWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeWidth().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getCircleStrokeWidth().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getCircleStrokeWidth().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testCircleStrokeColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-stroke-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleStrokeColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getCircleStrokeColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testCircleStrokeColorAsInt() {
+ public void testCircleStrokeColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleStrokeColor(
+ zoom(
+ exponential(
+ stop(2, circleStrokeColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeColor());
+ assertNotNull(layer.getCircleStrokeColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleStrokeColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleStrokeColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleStrokeColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleStrokeColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-stroke-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(circleStrokeColor(Color.RED));
- assertEquals(layer.getCircleStrokeColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ circleStrokeColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeColor());
+ assertNotNull(layer.getCircleStrokeColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleStrokeColor().getFunction().getStops().getClass());
}
@Test
- public void testCircleStrokeOpacity() {
+ public void testCircleStrokeColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ circleStrokeColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, circleStrokeColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeColor());
+ assertNotNull(layer.getCircleStrokeColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new CircleLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testCircleStrokeColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", circleStrokeColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeColor());
+ assertNotNull(layer.getCircleStrokeColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleStrokeColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleStrokeColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(circleStrokeColor(Color.RED));
+ assertEquals(layer.getCircleStrokeColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testCircleStrokeOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("circle-stroke-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(circleStrokeOpacity(0.3f));
assertEquals((Float) layer.getCircleStrokeOpacity().getValue(), (Float) 0.3f);
}
+ @Test
+ public void testCircleStrokeOpacityAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeOpacity(
+ zoom(
+ exponential(
+ stop(2, circleStrokeOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeOpacity());
+ assertNotNull(layer.getCircleStrokeOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getCircleStrokeOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getCircleStrokeOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getCircleStrokeOpacity().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testCircleStrokeOpacityAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeOpacity());
+ assertNotNull(layer.getCircleStrokeOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getCircleStrokeOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleStrokeOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, circleStrokeOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeOpacity());
+ assertNotNull(layer.getCircleStrokeOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testCircleStrokeOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, circleStrokeOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeOpacity());
+ assertNotNull(layer.getCircleStrokeOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getCircleStrokeOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getCircleStrokeOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getCircleStrokeOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getCircleStrokeOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testCircleStrokeOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("circle-stroke-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ circleStrokeOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, circleStrokeOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getCircleStrokeOpacity());
+ assertNotNull(layer.getCircleStrokeOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getCircleStrokeOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getCircleStrokeOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getCircleStrokeOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getCircleStrokeOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getCircleStrokeOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerStyleTest.java
deleted file mode 100644
index c8668fa407..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerStyleTest.java
+++ /dev/null
@@ -1,286 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.graphics.Color;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.FillLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillPattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for FillLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class FillLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private FillLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testFillAntialias() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-antialias");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillAntialias(true));
- assertEquals((Boolean) layer.getFillAntialias().getValue(), (Boolean) true);
- }
-
- @Test
- public void testFillOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillOpacity(0.3f));
- assertEquals((Float) layer.getFillOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testFillColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getFillColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testFillColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillColor(Color.RED));
- assertEquals(layer.getFillColorAsInt(), Color.RED);
- }
-
- @Test
- public void testFillOutlineColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-outline-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillOutlineColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getFillOutlineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testFillOutlineColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-outline-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillOutlineColor(Color.RED));
- assertEquals(layer.getFillOutlineColorAsInt(), Color.RED);
- }
-
- @Test
- public void testFillTranslate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-translate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getFillTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testFillTranslateAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-translate-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
- assertEquals((String) layer.getFillTranslateAnchor().getValue(), (String) FILL_TRANSLATE_ANCHOR_MAP);
- }
-
- @Test
- public void testFillPattern() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("fill-pattern");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(fillPattern("pedestrian-polygon"));
- assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon");
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 95360e1273..dd59b97525 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
@@ -1,12 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -18,21 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillPattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for FillLayer
@@ -53,12 +55,6 @@ public class FillLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
mapboxMap = rule.getActivity().getMapboxMap();
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
@@ -66,218 +62,551 @@ public class FillLayerTest extends BaseStyleTest {
layer = new FillLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
+ // Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
- Timber.i("visibility");
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testFillAntialias() {
+ public void testFillAntialiasAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
Timber.i("fill-antialias");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillAntialias(true));
assertEquals((Boolean) layer.getFillAntialias().getValue(), (Boolean) true);
}
@Test
- public void testFillOpacity() {
+ public void testFillAntialiasAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-antialias");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillAntialias(
+ zoom(
+ interval(
+ stop(2, fillAntialias(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillAntialias());
+ assertNotNull(layer.getFillAntialias().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillAntialias().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getFillAntialias().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getFillAntialias().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillOpacity(0.3f));
assertEquals((Float) layer.getFillOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testFillColor() {
+ public void testFillOpacityAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillOpacity(
+ zoom(
+ exponential(
+ stop(2, fillOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOpacity());
+ assertNotNull(layer.getFillOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillOpacity().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillOpacityAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOpacity());
+ assertNotNull(layer.getFillOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, fillOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOpacity());
+ assertNotNull(layer.getFillOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, fillOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOpacity());
+ assertNotNull(layer.getFillOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getFillOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testFillOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, fillOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOpacity());
+ assertNotNull(layer.getFillOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getFillOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getFillOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getFillOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getFillOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testFillColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getFillColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testFillColorAsInt() {
+ public void testFillColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillColor(
+ zoom(
+ exponential(
+ stop(2, fillColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillColor());
+ assertNotNull(layer.getFillColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(fillColor(Color.RED));
- assertEquals(layer.getFillColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ fillColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillColor());
+ assertNotNull(layer.getFillColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillColor().getFunction().getStops().getClass());
}
@Test
- public void testFillOutlineColor() {
+ public void testFillColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, fillColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillColor());
+ assertNotNull(layer.getFillColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", fillColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillColor());
+ assertNotNull(layer.getFillColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillColor(Color.RED));
+ assertEquals(layer.getFillColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testFillOutlineColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-outline-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillOutlineColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getFillOutlineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testFillOutlineColorAsInt() {
+ public void testFillOutlineColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-outline-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillOutlineColor(
+ zoom(
+ exponential(
+ stop(2, fillOutlineColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOutlineColor());
+ assertNotNull(layer.getFillOutlineColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillOutlineColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillOutlineColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillOutlineColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillOutlineColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillOutlineColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-outline-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(fillOutlineColor(Color.RED));
- assertEquals(layer.getFillOutlineColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ fillOutlineColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOutlineColor());
+ assertNotNull(layer.getFillOutlineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOutlineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOutlineColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getFillOutlineColor().getFunction().getStops().getClass());
}
@Test
- public void testFillTranslate() {
+ public void testFillOutlineColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-outline-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillOutlineColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, fillOutlineColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOutlineColor());
+ assertNotNull(layer.getFillOutlineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOutlineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOutlineColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getFillOutlineColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillOutlineColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-outline-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillOutlineColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", fillOutlineColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillOutlineColor());
+ assertNotNull(layer.getFillOutlineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getFillOutlineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getFillOutlineColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getFillOutlineColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testFillOutlineColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-outline-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(fillOutlineColor(Color.RED));
+ assertEquals(layer.getFillOutlineColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testFillTranslateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-translate");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(fillTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getFillTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(fillTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getFillTranslate().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testFillTranslateAnchor() {
+ public void testFillTranslateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-translate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillTranslate(
+ zoom(
+ exponential(
+ stop(2, fillTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillTranslate());
+ assertNotNull(layer.getFillTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getFillTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getFillTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getFillTranslate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillTranslateAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-translate-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
assertEquals((String) layer.getFillTranslateAnchor().getValue(), (String) FILL_TRANSLATE_ANCHOR_MAP);
}
@Test
- public void testFillPattern() {
+ public void testFillTranslateAnchorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-translate-anchor");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ fillTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillTranslateAnchor());
+ assertNotNull(layer.getFillTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getFillTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getFillTranslateAnchor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new FillLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testFillPatternAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("fill-pattern");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(fillPattern("pedestrian-polygon"));
assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon");
}
+ @Test
+ public void testFillPatternAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("fill-pattern");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ fillPattern(
+ zoom(
+ interval(
+ stop(2, fillPattern("pedestrian-polygon"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getFillPattern());
+ assertNotNull(layer.getFillPattern().getFunction());
+ assertEquals(CameraFunction.class, layer.getFillPattern().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getFillPattern().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getFillPattern().getFunction().getStops()).size());
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerStyleTest.java
deleted file mode 100644
index 47a38a11ab..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerStyleTest.java
+++ /dev/null
@@ -1,427 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.graphics.Color;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.LineLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_BUTT;
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_JOIN_BEVEL;
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineDasharray;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineGapWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineMiterLimit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.linePattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineRoundLimit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for LineLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class LineLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private LineLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testLineCap() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-cap");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineCap(LINE_CAP_BUTT));
- assertEquals((String) layer.getLineCap().getValue(), (String) LINE_CAP_BUTT);
- }
-
- @Test
- public void testLineJoin() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-join");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineJoin(LINE_JOIN_BEVEL));
- assertEquals((String) layer.getLineJoin().getValue(), (String) LINE_JOIN_BEVEL);
- }
-
- @Test
- public void testLineMiterLimit() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-miter-limit");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineMiterLimit(0.3f));
- assertEquals((Float) layer.getLineMiterLimit().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineRoundLimit() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-round-limit");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineRoundLimit(0.3f));
- assertEquals((Float) layer.getLineRoundLimit().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineOpacity(0.3f));
- assertEquals((Float) layer.getLineOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getLineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testLineColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineColor(Color.RED));
- assertEquals(layer.getLineColorAsInt(), Color.RED);
- }
-
- @Test
- public void testLineTranslate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-translate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getLineTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testLineTranslateAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-translate-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineTranslateAnchor(LINE_TRANSLATE_ANCHOR_MAP));
- assertEquals((String) layer.getLineTranslateAnchor().getValue(), (String) LINE_TRANSLATE_ANCHOR_MAP);
- }
-
- @Test
- public void testLineWidth() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-width");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineWidth(0.3f));
- assertEquals((Float) layer.getLineWidth().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineGapWidth() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-gap-width");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineGapWidth(0.3f));
- assertEquals((Float) layer.getLineGapWidth().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineOffset() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-offset");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineOffset(0.3f));
- assertEquals((Float) layer.getLineOffset().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineBlur() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-blur");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineBlur(0.3f));
- assertEquals((Float) layer.getLineBlur().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testLineDasharray() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-dasharray");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(lineDasharray(new Float[] {}));
- assertEquals((Float[]) layer.getLineDasharray().getValue(), (Float[]) new Float[] {});
- }
-
- @Test
- public void testLinePattern() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("line-pattern");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(linePattern("pedestrian-polygon"));
- assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon");
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 ad091c78b3..740393ad36 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
@@ -1,12 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -18,30 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_BUTT;
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_JOIN_BEVEL;
-import static com.mapbox.mapboxsdk.style.layers.Property.LINE_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineDasharray;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineGapWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineMiterLimit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.linePattern;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineRoundLimit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for LineLayer
@@ -62,12 +55,6 @@ public class LineLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
mapboxMap = rule.getActivity().getMapboxMap();
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
@@ -75,350 +62,1044 @@ public class LineLayerTest extends BaseStyleTest {
layer = new LineLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
+ // Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
- Timber.i("visibility");
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testLineCap() {
+ public void testLineCapAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
Timber.i("line-cap");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineCap(LINE_CAP_BUTT));
assertEquals((String) layer.getLineCap().getValue(), (String) LINE_CAP_BUTT);
}
@Test
- public void testLineJoin() {
+ public void testLineCapAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-cap");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineCap(
+ zoom(
+ interval(
+ stop(2, lineCap(LINE_CAP_BUTT))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineCap());
+ assertNotNull(layer.getLineCap().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineCap().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getLineCap().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getLineCap().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineJoinAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-join");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineJoin(LINE_JOIN_BEVEL));
assertEquals((String) layer.getLineJoin().getValue(), (String) LINE_JOIN_BEVEL);
}
@Test
- public void testLineMiterLimit() {
+ public void testLineJoinAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-join");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineJoin(
+ zoom(
+ interval(
+ stop(2, lineJoin(LINE_JOIN_BEVEL))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineJoin());
+ assertNotNull(layer.getLineJoin().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineJoin().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getLineJoin().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getLineJoin().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineMiterLimitAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-miter-limit");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineMiterLimit(0.3f));
assertEquals((Float) layer.getLineMiterLimit().getValue(), (Float) 0.3f);
}
@Test
- public void testLineRoundLimit() {
+ public void testLineMiterLimitAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-miter-limit");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineMiterLimit(
+ zoom(
+ exponential(
+ stop(2, lineMiterLimit(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineMiterLimit());
+ assertNotNull(layer.getLineMiterLimit().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineMiterLimit().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineMiterLimit().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineMiterLimit().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineMiterLimit().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineRoundLimitAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-round-limit");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineRoundLimit(0.3f));
assertEquals((Float) layer.getLineRoundLimit().getValue(), (Float) 0.3f);
}
@Test
- public void testLineOpacity() {
+ public void testLineRoundLimitAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-round-limit");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineRoundLimit(
+ zoom(
+ exponential(
+ stop(2, lineRoundLimit(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineRoundLimit());
+ assertNotNull(layer.getLineRoundLimit().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineRoundLimit().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineRoundLimit().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineRoundLimit().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineRoundLimit().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineOpacity(0.3f));
assertEquals((Float) layer.getLineOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testLineColor() {
+ public void testLineOpacityAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineOpacity(
+ zoom(
+ exponential(
+ stop(2, lineOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOpacity());
+ assertNotNull(layer.getLineOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineOpacity().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineOpacityAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOpacity());
+ assertNotNull(layer.getLineOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, lineOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOpacity());
+ assertNotNull(layer.getLineOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, lineOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOpacity());
+ assertNotNull(layer.getLineOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getLineOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testLineOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, lineOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOpacity());
+ assertNotNull(layer.getLineOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getLineOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getLineOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testLineColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getLineColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testLineColorAsInt() {
+ public void testLineColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineColor(
+ zoom(
+ exponential(
+ stop(2, lineColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineColor());
+ assertNotNull(layer.getLineColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(lineColor(Color.RED));
- assertEquals(layer.getLineColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ lineColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineColor());
+ assertNotNull(layer.getLineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineColor().getFunction().getStops().getClass());
}
@Test
- public void testLineTranslate() {
+ public void testLineColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, lineColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineColor());
+ assertNotNull(layer.getLineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", lineColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineColor());
+ assertNotNull(layer.getLineColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(lineColor(Color.RED));
+ assertEquals(layer.getLineColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testLineTranslateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-translate");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(lineTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getLineTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(lineTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getLineTranslate().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testLineTranslateAnchor() {
+ public void testLineTranslateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-translate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineTranslate(
+ zoom(
+ exponential(
+ stop(2, lineTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineTranslate());
+ assertNotNull(layer.getLineTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineTranslate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineTranslateAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-translate-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineTranslateAnchor(LINE_TRANSLATE_ANCHOR_MAP));
assertEquals((String) layer.getLineTranslateAnchor().getValue(), (String) LINE_TRANSLATE_ANCHOR_MAP);
}
@Test
- public void testLineWidth() {
+ public void testLineTranslateAnchorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-translate-anchor");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, lineTranslateAnchor(LINE_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineTranslateAnchor());
+ assertNotNull(layer.getLineTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getLineTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getLineTranslateAnchor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineWidth(0.3f));
assertEquals((Float) layer.getLineWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testLineGapWidth() {
+ public void testLineWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineWidth(
+ zoom(
+ exponential(
+ stop(2, lineWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineWidth());
+ assertNotNull(layer.getLineWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineGapWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-gap-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineGapWidth(0.3f));
assertEquals((Float) layer.getLineGapWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testLineOffset() {
+ public void testLineGapWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-gap-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineGapWidth(
+ zoom(
+ exponential(
+ stop(2, lineGapWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineGapWidth());
+ assertNotNull(layer.getLineGapWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineGapWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineGapWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineGapWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineGapWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineGapWidthAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-gap-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineGapWidth(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineGapWidth());
+ assertNotNull(layer.getLineGapWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineGapWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineGapWidth().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineGapWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineGapWidthAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-gap-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineGapWidth(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, lineGapWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineGapWidth());
+ assertNotNull(layer.getLineGapWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineGapWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineGapWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineGapWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineGapWidthAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-gap-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineGapWidth(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, lineGapWidth(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineGapWidth());
+ assertNotNull(layer.getLineGapWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineGapWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineGapWidth().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineGapWidth().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getLineGapWidth().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testLineGapWidthAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-gap-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineGapWidth(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, lineGapWidth(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineGapWidth());
+ assertNotNull(layer.getLineGapWidth().getFunction());
+ assertEquals(CompositeFunction.class, layer.getLineGapWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineGapWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineGapWidth().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getLineGapWidth().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineGapWidth().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testLineOffsetAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-offset");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineOffset(0.3f));
assertEquals((Float) layer.getLineOffset().getValue(), (Float) 0.3f);
}
@Test
- public void testLineBlur() {
+ public void testLineOffsetAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-offset");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineOffset(
+ zoom(
+ exponential(
+ stop(2, lineOffset(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOffset());
+ assertNotNull(layer.getLineOffset().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineOffset().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineOffset().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineOffset().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineOffset().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineOffsetAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOffset(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOffset());
+ assertNotNull(layer.getLineOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOffset().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineOffsetAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOffset(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, lineOffset(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOffset());
+ assertNotNull(layer.getLineOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOffset().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineOffsetAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOffset(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, lineOffset(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOffset());
+ assertNotNull(layer.getLineOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineOffset().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineOffset().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getLineOffset().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testLineOffsetAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineOffset(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, lineOffset(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineOffset());
+ assertNotNull(layer.getLineOffset().getFunction());
+ assertEquals(CompositeFunction.class, layer.getLineOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineOffset().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineOffset().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getLineOffset().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineOffset().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testLineBlurAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-blur");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(lineBlur(0.3f));
assertEquals((Float) layer.getLineBlur().getValue(), (Float) 0.3f);
}
@Test
- public void testLineDasharray() {
+ public void testLineBlurAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-blur");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineBlur(
+ zoom(
+ exponential(
+ stop(2, lineBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineBlur());
+ assertNotNull(layer.getLineBlur().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineBlur().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getLineBlur().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getLineBlur().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getLineBlur().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLineBlurAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineBlur(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineBlur());
+ assertNotNull(layer.getLineBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineBlur().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineBlurAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineBlur(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, lineBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineBlur());
+ assertNotNull(layer.getLineBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineBlurAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineBlur(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, lineBlur(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineBlur());
+ assertNotNull(layer.getLineBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineBlur().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineBlur().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getLineBlur().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testLineBlurAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineBlur(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, lineBlur(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineBlur());
+ assertNotNull(layer.getLineBlur().getFunction());
+ assertEquals(CompositeFunction.class, layer.getLineBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineBlur().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getLineBlur().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineBlur().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testLineDasharrayAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-dasharray");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(lineDasharray(new Float[] {}));
- assertEquals((Float[]) layer.getLineDasharray().getValue(), (Float[]) new Float[] {});
+ // Set and Get
+ layer.setProperties(lineDasharray(new Float[]{}));
+ assertEquals((Float[]) layer.getLineDasharray().getValue(), (Float[]) new Float[]{});
}
@Test
- public void testLinePattern() {
+ public void testLineDasharrayAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-dasharray");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ lineDasharray(
+ zoom(
+ interval(
+ stop(2, lineDasharray(new Float[]{}))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineDasharray());
+ assertNotNull(layer.getLineDasharray().getFunction());
+ assertEquals(CameraFunction.class, layer.getLineDasharray().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getLineDasharray().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getLineDasharray().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new LineLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testLinePatternAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("line-pattern");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(linePattern("pedestrian-polygon"));
assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon");
}
+ @Test
+ public void testLinePatternAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("line-pattern");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ linePattern(
+ zoom(
+ interval(
+ stop(2, linePattern("pedestrian-polygon"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLinePattern());
+ assertNotNull(layer.getLinePattern().getFunction());
+ assertEquals(CameraFunction.class, layer.getLinePattern().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getLinePattern().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getLinePattern().getFunction().getStops()).size());
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerStyleTest.java
deleted file mode 100644
index eb67b48f7a..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerStyleTest.java
+++ /dev/null
@@ -1,240 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.RasterLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMax;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMin;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterContrast;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterFadeDuration;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterHueRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterSaturation;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for RasterLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class RasterLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private RasterLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testRasterOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterOpacity(0.3f));
- assertEquals((Float) layer.getRasterOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterHueRotate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-hue-rotate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterHueRotate(0.3f));
- assertEquals((Float) layer.getRasterHueRotate().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterBrightnessMin() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-brightness-min");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterBrightnessMin(0.3f));
- assertEquals((Float) layer.getRasterBrightnessMin().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterBrightnessMax() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-brightness-max");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterBrightnessMax(0.3f));
- assertEquals((Float) layer.getRasterBrightnessMax().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterSaturation() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-saturation");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterSaturation(0.3f));
- assertEquals((Float) layer.getRasterSaturation().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterContrast() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-contrast");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterContrast(0.3f));
- assertEquals((Float) layer.getRasterContrast().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testRasterFadeDuration() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("raster-fade-duration");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(rasterFadeDuration(0.3f));
- assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f);
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 169d747b9c..eb2155f545 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
@@ -1,11 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
+import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -17,20 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMax;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterBrightnessMin;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterContrast;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterFadeDuration;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterHueRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.rasterSaturation;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for RasterLayer
@@ -51,12 +55,6 @@ public class RasterLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
mapboxMap = rule.getActivity().getMapboxMap();
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
@@ -64,174 +62,284 @@ public class RasterLayerTest extends BaseStyleTest {
layer = new RasterLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
+ // Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
- Timber.i("visibility");
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testRasterOpacity() {
+ public void testRasterOpacityAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
Timber.i("raster-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterOpacity(0.3f));
assertEquals((Float) layer.getRasterOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterHueRotate() {
+ public void testRasterOpacityAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterOpacity(
+ zoom(
+ exponential(
+ stop(2, rasterOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterOpacity());
+ assertNotNull(layer.getRasterOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterOpacity().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterHueRotateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-hue-rotate");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterHueRotate(0.3f));
assertEquals((Float) layer.getRasterHueRotate().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterBrightnessMin() {
+ public void testRasterHueRotateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-hue-rotate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterHueRotate(
+ zoom(
+ exponential(
+ stop(2, rasterHueRotate(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterHueRotate());
+ assertNotNull(layer.getRasterHueRotate().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterHueRotate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterHueRotate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterHueRotate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterHueRotate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterBrightnessMinAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-brightness-min");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterBrightnessMin(0.3f));
assertEquals((Float) layer.getRasterBrightnessMin().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterBrightnessMax() {
+ public void testRasterBrightnessMinAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-brightness-min");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterBrightnessMin(
+ zoom(
+ exponential(
+ stop(2, rasterBrightnessMin(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterBrightnessMin());
+ assertNotNull(layer.getRasterBrightnessMin().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterBrightnessMin().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterBrightnessMin().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterBrightnessMin().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterBrightnessMin().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterBrightnessMaxAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-brightness-max");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterBrightnessMax(0.3f));
assertEquals((Float) layer.getRasterBrightnessMax().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterSaturation() {
+ public void testRasterBrightnessMaxAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-brightness-max");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterBrightnessMax(
+ zoom(
+ exponential(
+ stop(2, rasterBrightnessMax(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterBrightnessMax());
+ assertNotNull(layer.getRasterBrightnessMax().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterBrightnessMax().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterBrightnessMax().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterBrightnessMax().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterBrightnessMax().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterSaturationAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-saturation");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterSaturation(0.3f));
assertEquals((Float) layer.getRasterSaturation().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterContrast() {
+ public void testRasterSaturationAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-saturation");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterSaturation(
+ zoom(
+ exponential(
+ stop(2, rasterSaturation(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterSaturation());
+ assertNotNull(layer.getRasterSaturation().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterSaturation().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterSaturation().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterSaturation().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterSaturation().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterContrastAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-contrast");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterContrast(0.3f));
assertEquals((Float) layer.getRasterContrast().getValue(), (Float) 0.3f);
}
@Test
- public void testRasterFadeDuration() {
+ public void testRasterContrastAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-contrast");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ rasterContrast(
+ zoom(
+ exponential(
+ stop(2, rasterContrast(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterContrast());
+ assertNotNull(layer.getRasterContrast().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterContrast().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterContrast().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterContrast().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterContrast().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new RasterLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testRasterFadeDurationAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("raster-fade-duration");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(rasterFadeDuration(0.3f));
assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f);
}
+ @Test
+ public void testRasterFadeDurationAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("raster-fade-duration");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ rasterFadeDuration(
+ zoom(
+ exponential(
+ stop(2, rasterFadeDuration(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getRasterFadeDuration());
+ assertNotNull(layer.getRasterFadeDuration().getFunction());
+ assertEquals(CameraFunction.class, layer.getRasterFadeDuration().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getRasterFadeDuration().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getRasterFadeDuration().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getRasterFadeDuration().getFunction().getStops()).size());
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleBackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleBackgroundLayerTest.java
index 762ae4f846..c95c959644 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleBackgroundLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleBackgroundLayerTest.java
@@ -44,10 +44,10 @@ public class RuntimeStyleBackgroundLayerTest
BackgroundLayer layer = mapboxMap.getLayerAs("background");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), Property.VISIBLE);
- //Set
+ // Set
layer.setProperties(PropertyFactory.visibility(Property.NONE));
assertEquals(layer.getVisibility().getValue(), Property.NONE);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
index eec00bdde9..bf90949ffd 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTests.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.testapp.style;
import android.graphics.Color;
+import android.graphics.PointF;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
@@ -10,12 +11,12 @@ import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
-import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
+import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
-import com.mapbox.mapboxsdk.style.sources.NoSuchSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.style.sources.VectorSource;
import com.mapbox.mapboxsdk.testapp.R;
@@ -32,12 +33,18 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.List;
+
+import timber.log.Timber;
+
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
/**
* Basic smoke tests for Layer and Source
@@ -57,139 +64,255 @@ public class RuntimeStyleTests {
}
@Test
+ public void testListLayers() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ List<Layer> layers = mapboxMap.getLayers();
+ assertNotNull(layers);
+ assertTrue(layers.size() > 0);
+ for (Layer layer : layers) {
+ assertNotNull(layer);
+ }
+ }
+
+ });
+ }
+
+ @Test
public void testGetAddRemoveLayer() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
onView(withId(R.id.mapView)).perform(new AddRemoveLayerAction());
}
@Test
+ public void testAddLayerAbove() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ List<Layer> layers = mapboxMap.getLayers();
+ Source source = mapboxMap.getSources().get(0);
+
+ // Test inserting with invalid above-id
+ try {
+ mapboxMap.addLayerAbove(new CircleLayer("invalid-id-layer-test", source.getId()), "no-such-layer-here-man");
+ fail("Should have thrown exception");
+ } catch (CannotAddLayerException ex) {
+ // Yeah
+ assertNotNull(ex.getMessage());
+ }
+
+ // Insert as last
+ CircleLayer last = new CircleLayer("this is the last one", source.getId());
+ mapboxMap.addLayerAbove(last, layers.get(layers.size() - 1).getId());
+ layers = mapboxMap.getLayers();
+ assertEquals(last.getId(), layers.get(layers.size() - 1).getId());
+
+ // Insert
+ CircleLayer second = new CircleLayer("this is the second one", source.getId());
+ mapboxMap.addLayerAbove(second, layers.get(0).getId());
+ layers = mapboxMap.getLayers();
+ assertEquals(second.getId(), layers.get(1).getId());
+ }
+ });
+ }
+
+ @Test
+ public void testRemoveLayerAt() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ // Remove by index
+ Layer firstLayer = mapboxMap.getLayers().get(0);
+ Layer removed = mapboxMap.removeLayerAt(0);
+ assertNotNull(removed);
+ assertNotNull(removed.getId());
+ assertEquals(firstLayer.getId(), removed.getId());
+
+ // Test remove by index bounds checks
+ Timber.i("Remove layer at index > size");
+ assertNull(mapboxMap.removeLayerAt(Integer.MAX_VALUE));
+ }
+ });
+ }
+
+ public void testAddLayerAt() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ List<Layer> layers = mapboxMap.getLayers();
+ Source source = mapboxMap.getSources().get(0);
+
+ // Test inserting out of range
+ try {
+ mapboxMap.addLayerAt(new CircleLayer("invalid-id-layer-test", source.getId()), layers.size());
+ fail("Should have thrown exception");
+ } catch (CannotAddLayerException ex) {
+ // Yeah
+ assertNotNull(ex.getMessage());
+ }
+
+ // Insert at current last position
+ CircleLayer last = new CircleLayer("this is the last one", source.getId());
+ mapboxMap.addLayerAt(last, layers.size() - 1);
+ layers = mapboxMap.getLayers();
+ assertEquals(last.getId(), layers.get(layers.size() - 2).getId());
+
+ // Insert at start
+ CircleLayer second = new CircleLayer("this is the first one", source.getId());
+ mapboxMap.addLayerAt(second, 0);
+ layers = mapboxMap.getLayers();
+ assertEquals(second.getId(), layers.get(0).getId());
+ }
+ });
+ }
+
+
+ @Test
+ public void testListSources() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+
+ List<Source> sources = mapboxMap.getSources();
+ assertNotNull(sources);
+ assertTrue(sources.size() > 0);
+ for (Source source : sources) {
+ assertNotNull(source);
+ }
+ }
+
+ });
+ }
+
+ @Test
public void testAddRemoveSource() {
ViewUtils.checkViewIsDisplayed(R.id.mapView);
MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
mapboxMap.addSource(new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2"));
- try {
- mapboxMap.removeSource("my-source");
- } catch (NoSuchSourceException noSuchSourceException) {
- // it's ok..
- }
+ mapboxMap.removeSource("my-source");
onView(withId(R.id.mapView)).perform(new AddRemoveSourceAction());
}
- private class AddRemoveLayerAction implements ViewAction {
+ /**
+ * https://github.com/mapbox/mapbox-gl-native/issues/7973
+ */
+ @Test
+ public void testQueryRenderedFeaturesInputHandling() {
+ ViewUtils.checkViewIsDisplayed(R.id.mapView);
+ onView(withId(R.id.mapView)).perform(new BaseViewAction() {
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
+ String[] layerIds = new String[600];
+ for (int i = 0; i < layerIds.length; i++) {
+ layerIds[i] = "layer-" + i;
+ }
+ mapboxMap.queryRenderedFeatures(new PointF(100, 100), layerIds);
+ }
- @Override
- public Matcher<View> getConstraints() {
- return isDisplayed();
- }
+ });
+ }
- @Override
- public String getDescription() {
- return getClass().getSimpleName();
- }
+ private class AddRemoveLayerAction extends BaseViewAction {
@Override
public void perform(UiController uiController, View view) {
MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
- //Get initial
+ // Get initial
assertNotNull(mapboxMap.getLayer("building"));
- //Remove
- try {
- mapboxMap.removeLayer("building");
- } catch (NoSuchLayerException noSuchSourceException) {
- fail("Definitively exists: " + noSuchSourceException.getMessage());
- }
+ // Remove
+ Layer building = mapboxMap.removeLayer("building");
+ assertNotNull(building);
assertNull(mapboxMap.getLayer("building"));
- //Add
+ // Add
FillLayer layer = new FillLayer("building", "composite");
layer.setSourceLayer("building");
mapboxMap.addLayer(layer);
assertNotNull(mapboxMap.getLayer("building"));
- //Assure the reference still works
+ // Assure the reference still works
layer.setProperties(PropertyFactory.visibility(Property.VISIBLE));
- //Remove, preserving the reference
- try {
- mapboxMap.removeLayer(layer);
- } catch (NoSuchLayerException noSuchSourceException) {
- fail("Definitively exists: " + noSuchSourceException.getMessage());
- }
+ // Remove, preserving the reference
+ mapboxMap.removeLayer(layer);
- //Property setters should still work
+ // Property setters should still work
layer.setProperties(PropertyFactory.fillColor(Color.RED));
- //Re-add the reference...
+ // Re-add the reference...
mapboxMap.addLayer(layer);
- //Ensure it's there
+ // Ensure it's there
Assert.assertNotNull(mapboxMap.getLayer(layer.getId()));
- //Test adding a duplicate layer
+ // Test adding a duplicate layer
try {
mapboxMap.addLayer(new FillLayer("building", "composite"));
fail("Should not have been allowed to add a layer with a duplicate id");
} catch (CannotAddLayerException cannotAddLayerException) {
- //OK
+ // OK
}
}
}
- private class AddRemoveSourceAction implements ViewAction {
-
- @Override
- public Matcher<View> getConstraints() {
- return isDisplayed();
- }
-
- @Override
- public String getDescription() {
- return getClass().getSimpleName();
- }
+ private class AddRemoveSourceAction extends BaseViewAction {
@Override
public void perform(UiController uiController, View view) {
MapboxMap mapboxMap = rule.getActivity().getMapboxMap();
- //Add initial source
+ // Add initial source
mapboxMap.addSource(new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2"));
- //Remove
- try {
- mapboxMap.removeSource("my-source");
- } catch (NoSuchSourceException noSuchSourceException) {
- fail("Definitively exists: " + noSuchSourceException.getMessage());
- }
+ // Remove
+ Source mySource = mapboxMap.removeSource("my-source");
+ assertNotNull(mySource);
assertNull(mapboxMap.getLayer("my-source"));
- //Add
+ // Add
Source source = new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2");
mapboxMap.addSource(source);
- //Remove, preserving the reference
- try {
- mapboxMap.removeSource(source);
- } catch (NoSuchSourceException noSuchSourceException) {
- fail("Definitively exists: " + noSuchSourceException.getMessage());
- }
+ // Remove, preserving the reference
+ mapboxMap.removeSource(source);
- //Re-add the reference...
+ // Re-add the reference...
mapboxMap.addSource(source);
- //Ensure it's there
+ // Ensure it's there
Assert.assertNotNull(mapboxMap.getSource(source.getId()));
- //Test adding a duplicate source
+ // Test adding a duplicate source
try {
Source source2 = new VectorSource("my-source", "mapbox://mapbox.mapbox-terrain-v2");
mapboxMap.addSource(source2);
fail("Should not have been allowed to add a source with a duplicate id");
} catch (CannotAddSourceException cannotAddSourceException) {
- //OK
+ // OK
}
}
}
@@ -198,4 +321,18 @@ public class RuntimeStyleTests {
public void unregisterIntentServiceIdlingResource() {
Espresso.unregisterIdlingResources(idlingResource);
}
+
+ public abstract class BaseViewAction implements ViewAction {
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
index 57b0fe72ff..400c5fbc3c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RuntimeStyleTimingTests.java
@@ -35,7 +35,7 @@ public class RuntimeStyleTimingTests extends BaseStyleTest {
@Test
public void testGetAddRemoveLayer() {
checkViewIsDisplayed(R.id.mapView);
- //We're good if it didn't crash
+ // We're good if it didn't crash
}
@After
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerStyleTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerStyleTest.java
deleted file mode 100644
index 5b59d4ceae..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerStyleTest.java
+++ /dev/null
@@ -1,1283 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.style;
-// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make style-code-android`.
-
-import android.graphics.Color;
-import android.support.test.espresso.Espresso;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ROTATION_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TEXT_FIT_NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.SYMBOL_PLACEMENT_POINT;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ANCHOR_CENTER;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_JUSTIFY_LEFT;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_PITCH_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ROTATION_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSFORM_NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconKeepUpright;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOptional;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotationAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFitPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolAvoidEdges;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolSpacing;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textJustify;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textKeepUpright;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLetterSpacing;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLineHeight;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxAngle;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOptional;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPitchAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotationAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTransform;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Basic smoke tests for SymbolLayer
- */
-@RunWith(AndroidJUnit4.class)
-public class SymbolLayerStyleTest extends BaseStyleTest {
-
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
-
- private SymbolLayer layer;
-
- private OnMapReadyIdlingResource idlingResource;
-
- private MapboxMap mapboxMap;
-
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("visibility");
- assertNotNull(layer);
-
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
-
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
-
- @Test
- public void testSymbolPlacement() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("symbol-placement");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(symbolPlacement(SYMBOL_PLACEMENT_POINT));
- assertEquals((String) layer.getSymbolPlacement().getValue(), (String) SYMBOL_PLACEMENT_POINT);
- }
-
- @Test
- public void testSymbolSpacing() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("symbol-spacing");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(symbolSpacing(0.3f));
- assertEquals((Float) layer.getSymbolSpacing().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testSymbolAvoidEdges() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("symbol-avoid-edges");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(symbolAvoidEdges(true));
- assertEquals((Boolean) layer.getSymbolAvoidEdges().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconAllowOverlap() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-allow-overlap");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconAllowOverlap(true));
- assertEquals((Boolean) layer.getIconAllowOverlap().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconIgnorePlacement() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-ignore-placement");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconIgnorePlacement(true));
- assertEquals((Boolean) layer.getIconIgnorePlacement().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconOptional() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-optional");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconOptional(true));
- assertEquals((Boolean) layer.getIconOptional().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconRotationAlignment() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-rotation-alignment");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconRotationAlignment(ICON_ROTATION_ALIGNMENT_MAP));
- assertEquals((String) layer.getIconRotationAlignment().getValue(), (String) ICON_ROTATION_ALIGNMENT_MAP);
- }
-
- @Test
- public void testIconSize() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-size");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconSize(0.3f));
- assertEquals((Float) layer.getIconSize().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconTextFit() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-text-fit");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconTextFit(ICON_TEXT_FIT_NONE));
- assertEquals((String) layer.getIconTextFit().getValue(), (String) ICON_TEXT_FIT_NONE);
- }
-
- @Test
- public void testIconTextFitPadding() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-text-fit-padding");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconTextFitPadding(new Float[] {0f, 0f, 0f, 0f}));
- assertEquals((Float[]) layer.getIconTextFitPadding().getValue(), (Float[]) new Float[] {0f, 0f, 0f, 0f});
- }
-
- @Test
- public void testIconImage() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-image");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconImage("undefined"));
- assertEquals((String) layer.getIconImage().getValue(), (String) "undefined");
- }
-
- @Test
- public void testIconRotate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-rotate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconRotate(0.3f));
- assertEquals((Float) layer.getIconRotate().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconPadding() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-padding");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconPadding(0.3f));
- assertEquals((Float) layer.getIconPadding().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconKeepUpright() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-keep-upright");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconKeepUpright(true));
- assertEquals((Boolean) layer.getIconKeepUpright().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconOffset() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-offset");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconOffset(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getIconOffset().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testTextPitchAlignment() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-pitch-alignment");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textPitchAlignment(TEXT_PITCH_ALIGNMENT_MAP));
- assertEquals((String) layer.getTextPitchAlignment().getValue(), (String) TEXT_PITCH_ALIGNMENT_MAP);
- }
-
- @Test
- public void testTextRotationAlignment() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-rotation-alignment");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textRotationAlignment(TEXT_ROTATION_ALIGNMENT_MAP));
- assertEquals((String) layer.getTextRotationAlignment().getValue(), (String) TEXT_ROTATION_ALIGNMENT_MAP);
- }
-
- @Test
- public void testTextField() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-field");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textField(""));
- assertEquals((String) layer.getTextField().getValue(), (String) "");
- }
-
- @Test
- public void testTextFont() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-font");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textFont(new String[] {"Open Sans Regular", "Arial Unicode MS Regular"}));
- assertEquals((String[]) layer.getTextFont().getValue(), (String[]) new String[] {"Open Sans Regular",
- "Arial Unicode MS Regular"});
- }
-
- @Test
- public void testTextSize() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-size");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textSize(0.3f));
- assertEquals((Float) layer.getTextSize().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextMaxWidth() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-max-width");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textMaxWidth(0.3f));
- assertEquals((Float) layer.getTextMaxWidth().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextLineHeight() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-line-height");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textLineHeight(0.3f));
- assertEquals((Float) layer.getTextLineHeight().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextLetterSpacing() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-letter-spacing");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textLetterSpacing(0.3f));
- assertEquals((Float) layer.getTextLetterSpacing().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextJustify() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-justify");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textJustify(TEXT_JUSTIFY_LEFT));
- assertEquals((String) layer.getTextJustify().getValue(), (String) TEXT_JUSTIFY_LEFT);
- }
-
- @Test
- public void testTextAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textAnchor(TEXT_ANCHOR_CENTER));
- assertEquals((String) layer.getTextAnchor().getValue(), (String) TEXT_ANCHOR_CENTER);
- }
-
- @Test
- public void testTextMaxAngle() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-max-angle");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textMaxAngle(0.3f));
- assertEquals((Float) layer.getTextMaxAngle().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextRotate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-rotate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textRotate(0.3f));
- assertEquals((Float) layer.getTextRotate().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextPadding() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-padding");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textPadding(0.3f));
- assertEquals((Float) layer.getTextPadding().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextKeepUpright() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-keep-upright");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textKeepUpright(true));
- assertEquals((Boolean) layer.getTextKeepUpright().getValue(), (Boolean) true);
- }
-
- @Test
- public void testTextTransform() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-transform");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textTransform(TEXT_TRANSFORM_NONE));
- assertEquals((String) layer.getTextTransform().getValue(), (String) TEXT_TRANSFORM_NONE);
- }
-
- @Test
- public void testTextOffset() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-offset");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textOffset(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getTextOffset().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testTextAllowOverlap() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-allow-overlap");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textAllowOverlap(true));
- assertEquals((Boolean) layer.getTextAllowOverlap().getValue(), (Boolean) true);
- }
-
- @Test
- public void testTextIgnorePlacement() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-ignore-placement");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textIgnorePlacement(true));
- assertEquals((Boolean) layer.getTextIgnorePlacement().getValue(), (Boolean) true);
- }
-
- @Test
- public void testTextOptional() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-optional");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textOptional(true));
- assertEquals((Boolean) layer.getTextOptional().getValue(), (Boolean) true);
- }
-
- @Test
- public void testIconOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconOpacity(0.3f));
- assertEquals((Float) layer.getIconOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getIconColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testIconColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconColor(Color.RED));
- assertEquals(layer.getIconColorAsInt(), Color.RED);
- }
-
- @Test
- public void testIconHaloColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-halo-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconHaloColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getIconHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testIconHaloColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-halo-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconHaloColor(Color.RED));
- assertEquals(layer.getIconHaloColorAsInt(), Color.RED);
- }
-
- @Test
- public void testIconHaloWidth() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-halo-width");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconHaloWidth(0.3f));
- assertEquals((Float) layer.getIconHaloWidth().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconHaloBlur() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-halo-blur");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconHaloBlur(0.3f));
- assertEquals((Float) layer.getIconHaloBlur().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testIconTranslate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-translate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getIconTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testIconTranslateAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("icon-translate-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(iconTranslateAnchor(ICON_TRANSLATE_ANCHOR_MAP));
- assertEquals((String) layer.getIconTranslateAnchor().getValue(), (String) ICON_TRANSLATE_ANCHOR_MAP);
- }
-
- @Test
- public void testTextOpacity() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-opacity");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textOpacity(0.3f));
- assertEquals((Float) layer.getTextOpacity().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getTextColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testTextColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textColor(Color.RED));
- assertEquals(layer.getTextColorAsInt(), Color.RED);
- }
-
- @Test
- public void testTextHaloColor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-halo-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textHaloColor("rgba(0, 0, 0, 1)"));
- assertEquals((String) layer.getTextHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
- }
-
- @Test
- public void testTextHaloColorAsInt() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-halo-color");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textHaloColor(Color.RED));
- assertEquals(layer.getTextHaloColorAsInt(), Color.RED);
- }
-
- @Test
- public void testTextHaloWidth() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-halo-width");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textHaloWidth(0.3f));
- assertEquals((Float) layer.getTextHaloWidth().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextHaloBlur() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-halo-blur");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textHaloBlur(0.3f));
- assertEquals((Float) layer.getTextHaloBlur().getValue(), (Float) 0.3f);
- }
-
- @Test
- public void testTextTranslate() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-translate");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getTextTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
- }
-
- @Test
- public void testTextTranslateAnchor() {
- checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
- Timber.i("text-translate-anchor");
- assertNotNull(layer);
-
- //Set and Get
- layer.setProperties(textTranslateAnchor(TEXT_TRANSLATE_ANCHOR_MAP));
- assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP);
- }
-
-
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
-}
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 f4c50a2ffb..3b3bc9c8b5 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
@@ -1,12 +1,23 @@
-package com.mapbox.mapboxsdk.testapp.style;
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+package com.mapbox.mapboxsdk.testapp.style;
+
import android.graphics.Color;
import android.support.test.espresso.Espresso;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -18,71 +29,12 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import timber.log.Timber;
-
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ROTATION_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TEXT_FIT_NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.ICON_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.SYMBOL_PLACEMENT_POINT;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ANCHOR_CENTER;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_JUSTIFY_LEFT;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_PITCH_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ROTATION_ALIGNMENT_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSFORM_NONE;
-import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_TRANSLATE_ANCHOR_MAP;
-import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconHaloWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconKeepUpright;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOptional;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotationAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFit;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTextFitPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolAvoidEdges;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolSpacing;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloBlur;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloColor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textHaloWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textJustify;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textKeepUpright;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLetterSpacing;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textLineHeight;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxAngle;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textMaxWidth;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOffset;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOpacity;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textOptional;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPadding;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textPitchAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotationAlignment;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTransform;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslate;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textTranslateAnchor;
-import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
+import static org.junit.Assert.*;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
/**
* Basic smoke tests for SymbolLayer
@@ -103,12 +55,6 @@ public class SymbolLayerTest extends BaseStyleTest {
public void setup() {
idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
Espresso.registerIdlingResources(idlingResource);
- }
-
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
-
mapboxMap = rule.getActivity().getMapboxMap();
if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
@@ -116,1165 +62,2984 @@ public class SymbolLayerTest extends BaseStyleTest {
layer = new SymbolLayer("my-layer", "composite");
layer.setSourceLayer("composite");
mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
+ // Layer reference is now stale, get new reference
layer = mapboxMap.getLayerAs("my-layer");
}
- Timber.i("visibility");
+ }
+
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
assertNotNull(layer);
- //Get initial
+ // Get initial
assertEquals(layer.getVisibility().getValue(), VISIBLE);
- //Set
+ // Set
layer.setProperties(visibility(NONE));
assertEquals(layer.getVisibility().getValue(), NONE);
}
@Test
- public void testSymbolPlacement() {
+ public void testSymbolPlacementAsConstant() {
checkViewIsDisplayed(R.id.mapView);
-
- mapboxMap = rule.getActivity().getMapboxMap();
-
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
Timber.i("symbol-placement");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(symbolPlacement(SYMBOL_PLACEMENT_POINT));
assertEquals((String) layer.getSymbolPlacement().getValue(), (String) SYMBOL_PLACEMENT_POINT);
}
@Test
- public void testSymbolSpacing() {
+ public void testSymbolPlacementAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("symbol-placement");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ symbolPlacement(
+ zoom(
+ interval(
+ stop(2, symbolPlacement(SYMBOL_PLACEMENT_POINT))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getSymbolPlacement());
+ assertNotNull(layer.getSymbolPlacement().getFunction());
+ assertEquals(CameraFunction.class, layer.getSymbolPlacement().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getSymbolPlacement().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getSymbolPlacement().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testSymbolSpacingAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("symbol-spacing");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(symbolSpacing(0.3f));
assertEquals((Float) layer.getSymbolSpacing().getValue(), (Float) 0.3f);
}
@Test
- public void testSymbolAvoidEdges() {
+ public void testSymbolSpacingAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("symbol-spacing");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ symbolSpacing(
+ zoom(
+ exponential(
+ stop(2, symbolSpacing(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getSymbolSpacing());
+ assertNotNull(layer.getSymbolSpacing().getFunction());
+ assertEquals(CameraFunction.class, layer.getSymbolSpacing().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getSymbolSpacing().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getSymbolSpacing().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getSymbolSpacing().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testSymbolAvoidEdgesAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("symbol-avoid-edges");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(symbolAvoidEdges(true));
assertEquals((Boolean) layer.getSymbolAvoidEdges().getValue(), (Boolean) true);
}
@Test
- public void testIconAllowOverlap() {
+ public void testSymbolAvoidEdgesAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("symbol-avoid-edges");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ symbolAvoidEdges(
+ zoom(
+ interval(
+ stop(2, symbolAvoidEdges(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getSymbolAvoidEdges());
+ assertNotNull(layer.getSymbolAvoidEdges().getFunction());
+ assertEquals(CameraFunction.class, layer.getSymbolAvoidEdges().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getSymbolAvoidEdges().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getSymbolAvoidEdges().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconAllowOverlapAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-allow-overlap");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconAllowOverlap(true));
assertEquals((Boolean) layer.getIconAllowOverlap().getValue(), (Boolean) true);
}
@Test
- public void testIconIgnorePlacement() {
+ public void testIconAllowOverlapAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-allow-overlap");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconAllowOverlap(
+ zoom(
+ interval(
+ stop(2, iconAllowOverlap(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconAllowOverlap());
+ assertNotNull(layer.getIconAllowOverlap().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconAllowOverlap().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconAllowOverlap().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconAllowOverlap().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconIgnorePlacementAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-ignore-placement");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconIgnorePlacement(true));
assertEquals((Boolean) layer.getIconIgnorePlacement().getValue(), (Boolean) true);
}
@Test
- public void testIconOptional() {
+ public void testIconIgnorePlacementAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-ignore-placement");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconIgnorePlacement(
+ zoom(
+ interval(
+ stop(2, iconIgnorePlacement(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconIgnorePlacement());
+ assertNotNull(layer.getIconIgnorePlacement().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconIgnorePlacement().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconIgnorePlacement().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconIgnorePlacement().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconOptionalAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-optional");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconOptional(true));
assertEquals((Boolean) layer.getIconOptional().getValue(), (Boolean) true);
}
@Test
- public void testIconRotationAlignment() {
+ public void testIconOptionalAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-optional");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconOptional(
+ zoom(
+ interval(
+ stop(2, iconOptional(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOptional());
+ assertNotNull(layer.getIconOptional().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconOptional().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconOptional().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconOptional().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconRotationAlignmentAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-rotation-alignment");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconRotationAlignment(ICON_ROTATION_ALIGNMENT_MAP));
assertEquals((String) layer.getIconRotationAlignment().getValue(), (String) ICON_ROTATION_ALIGNMENT_MAP);
}
@Test
- public void testIconSize() {
+ public void testIconRotationAlignmentAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotation-alignment");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconRotationAlignment(
+ zoom(
+ interval(
+ stop(2, iconRotationAlignment(ICON_ROTATION_ALIGNMENT_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotationAlignment());
+ assertNotNull(layer.getIconRotationAlignment().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconRotationAlignment().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconRotationAlignment().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconRotationAlignment().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconSizeAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-size");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconSize(0.3f));
assertEquals((Float) layer.getIconSize().getValue(), (Float) 0.3f);
}
@Test
- public void testIconTextFit() {
+ public void testIconSizeAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-size");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconSize(
+ zoom(
+ exponential(
+ stop(2, iconSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconSize());
+ assertNotNull(layer.getIconSize().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconSize().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconSize().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconSize().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconSize().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconTextFitAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-text-fit");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconTextFit(ICON_TEXT_FIT_NONE));
assertEquals((String) layer.getIconTextFit().getValue(), (String) ICON_TEXT_FIT_NONE);
}
@Test
- public void testIconTextFitPadding() {
+ public void testIconTextFitAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-text-fit");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconTextFit(
+ zoom(
+ interval(
+ stop(2, iconTextFit(ICON_TEXT_FIT_NONE))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconTextFit());
+ assertNotNull(layer.getIconTextFit().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconTextFit().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconTextFit().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconTextFit().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconTextFitPaddingAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-text-fit-padding");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(iconTextFitPadding(new Float[] {0f, 0f, 0f, 0f}));
- assertEquals((Float[]) layer.getIconTextFitPadding().getValue(), (Float[]) new Float[] {0f, 0f, 0f, 0f});
+ // Set and Get
+ layer.setProperties(iconTextFitPadding(new Float[]{0f,0f,0f,0f}));
+ assertEquals((Float[]) layer.getIconTextFitPadding().getValue(), (Float[]) new Float[]{0f,0f,0f,0f});
}
@Test
- public void testIconImage() {
+ public void testIconTextFitPaddingAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-text-fit-padding");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconTextFitPadding(
+ zoom(
+ exponential(
+ stop(2, iconTextFitPadding(new Float[]{0f,0f,0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconTextFitPadding());
+ assertNotNull(layer.getIconTextFitPadding().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconTextFitPadding().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconTextFitPadding().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconTextFitPadding().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconTextFitPadding().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconImageAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-image");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconImage("undefined"));
assertEquals((String) layer.getIconImage().getValue(), (String) "undefined");
}
@Test
- public void testIconRotate() {
+ public void testIconImageAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-image");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconImage(
+ zoom(
+ interval(
+ stop(2, iconImage("undefined"))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconImage());
+ assertNotNull(layer.getIconImage().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconImage().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconImage().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconImage().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconRotateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-rotate");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconRotate(0.3f));
assertEquals((Float) layer.getIconRotate().getValue(), (Float) 0.3f);
}
@Test
- public void testIconPadding() {
+ public void testIconRotateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconRotate(
+ zoom(
+ exponential(
+ stop(2, iconRotate(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotate());
+ assertNotNull(layer.getIconRotate().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconRotate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconRotate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconRotate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconRotate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconRotateAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconRotate(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotate());
+ assertNotNull(layer.getIconRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconRotate().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconRotate().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconRotateAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconRotate(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconRotate(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotate());
+ assertNotNull(layer.getIconRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconRotate().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconRotate().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconRotateAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconRotate(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconRotate(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotate());
+ assertNotNull(layer.getIconRotate().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconRotate().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconRotate().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconRotate().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testIconRotateAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-rotate");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconRotate(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconRotate(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconRotate());
+ assertNotNull(layer.getIconRotate().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconRotate().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconRotate().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconRotate().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconRotate().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconRotate().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testIconPaddingAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-padding");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconPadding(0.3f));
assertEquals((Float) layer.getIconPadding().getValue(), (Float) 0.3f);
}
@Test
- public void testIconKeepUpright() {
+ public void testIconPaddingAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-padding");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconPadding(
+ zoom(
+ exponential(
+ stop(2, iconPadding(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconPadding());
+ assertNotNull(layer.getIconPadding().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconPadding().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconPadding().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconPadding().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconPadding().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconKeepUprightAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-keep-upright");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconKeepUpright(true));
assertEquals((Boolean) layer.getIconKeepUpright().getValue(), (Boolean) true);
}
@Test
- public void testIconOffset() {
+ public void testIconKeepUprightAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-keep-upright");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconKeepUpright(
+ zoom(
+ interval(
+ stop(2, iconKeepUpright(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconKeepUpright());
+ assertNotNull(layer.getIconKeepUpright().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconKeepUpright().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconKeepUpright().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconKeepUpright().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconOffsetAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-offset");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(iconOffset(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getIconOffset().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(iconOffset(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getIconOffset().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testTextPitchAlignment() {
+ public void testIconOffsetAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-offset");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconOffset(
+ zoom(
+ exponential(
+ stop(2, iconOffset(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOffset());
+ assertNotNull(layer.getIconOffset().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconOffset().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconOffset().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconOffset().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconOffset().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconOffsetAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOffset(property("FeaturePropertyA", Stops.<Float[]>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOffset());
+ assertNotNull(layer.getIconOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOffset().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconOffsetAsIntervalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-offset");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOffset(
+ property(
+ "FeaturePropertyA",
+ interval(
+ stop(1, iconOffset(new Float[]{0f,0f}))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOffset());
+ assertNotNull(layer.getIconOffset().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconOffset().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOffset().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.getIconOffset().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextPitchAlignmentAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-pitch-alignment");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textPitchAlignment(TEXT_PITCH_ALIGNMENT_MAP));
assertEquals((String) layer.getTextPitchAlignment().getValue(), (String) TEXT_PITCH_ALIGNMENT_MAP);
}
@Test
- public void testTextRotationAlignment() {
+ public void testTextPitchAlignmentAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-pitch-alignment");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textPitchAlignment(
+ zoom(
+ interval(
+ stop(2, textPitchAlignment(TEXT_PITCH_ALIGNMENT_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextPitchAlignment());
+ assertNotNull(layer.getTextPitchAlignment().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextPitchAlignment().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextPitchAlignment().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextPitchAlignment().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextRotationAlignmentAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-rotation-alignment");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textRotationAlignment(TEXT_ROTATION_ALIGNMENT_MAP));
assertEquals((String) layer.getTextRotationAlignment().getValue(), (String) TEXT_ROTATION_ALIGNMENT_MAP);
}
@Test
- public void testTextField() {
+ public void testTextRotationAlignmentAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-rotation-alignment");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textRotationAlignment(
+ zoom(
+ interval(
+ stop(2, textRotationAlignment(TEXT_ROTATION_ALIGNMENT_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotationAlignment());
+ assertNotNull(layer.getTextRotationAlignment().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextRotationAlignment().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextRotationAlignment().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextRotationAlignment().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextFieldAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-field");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textField(""));
assertEquals((String) layer.getTextField().getValue(), (String) "");
}
@Test
- public void testTextFont() {
+ public void testTextFieldAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-field");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textField(
+ zoom(
+ interval(
+ stop(2, textField(""))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextField());
+ assertNotNull(layer.getTextField().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextField().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextField().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextField().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextFieldAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-field");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textField(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextField());
+ assertNotNull(layer.getTextField().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextField().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextField().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextField().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextFieldAsIntervalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-field");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textField(
+ property(
+ "FeaturePropertyA",
+ interval(
+ stop(1, textField(""))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextField());
+ assertNotNull(layer.getTextField().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextField().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextField().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.getTextField().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextFontAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-font");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(textFont(new String[] {"Open Sans Regular", "Arial Unicode MS Regular"}));
- assertEquals((String[]) layer.getTextFont().getValue(), (String[]) new String[] {"Open Sans Regular",
- "Arial Unicode MS Regular"});
+ // Set and Get
+ layer.setProperties(textFont(new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}));
+ assertEquals((String[]) layer.getTextFont().getValue(), (String[]) new String[]{"Open Sans Regular", "Arial Unicode MS Regular"});
}
@Test
- public void testTextSize() {
+ public void testTextFontAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-font");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textFont(
+ zoom(
+ interval(
+ stop(2, textFont(new String[]{"Open Sans Regular", "Arial Unicode MS Regular"}))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextFont());
+ assertNotNull(layer.getTextFont().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextFont().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextFont().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextFont().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextSizeAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-size");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textSize(0.3f));
assertEquals((Float) layer.getTextSize().getValue(), (Float) 0.3f);
}
@Test
- public void testTextMaxWidth() {
+ public void testTextSizeAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-size");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textSize(
+ zoom(
+ exponential(
+ stop(2, textSize(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextSize());
+ assertNotNull(layer.getTextSize().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextSize().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextSize().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextSize().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextSize().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextMaxWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-max-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textMaxWidth(0.3f));
assertEquals((Float) layer.getTextMaxWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testTextLineHeight() {
+ public void testTextMaxWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-max-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textMaxWidth(
+ zoom(
+ exponential(
+ stop(2, textMaxWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextMaxWidth());
+ assertNotNull(layer.getTextMaxWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextMaxWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextMaxWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextMaxWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextMaxWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextLineHeightAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-line-height");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textLineHeight(0.3f));
assertEquals((Float) layer.getTextLineHeight().getValue(), (Float) 0.3f);
}
@Test
- public void testTextLetterSpacing() {
+ public void testTextLineHeightAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-line-height");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textLineHeight(
+ zoom(
+ exponential(
+ stop(2, textLineHeight(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextLineHeight());
+ assertNotNull(layer.getTextLineHeight().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextLineHeight().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextLineHeight().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextLineHeight().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextLineHeight().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextLetterSpacingAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-letter-spacing");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textLetterSpacing(0.3f));
assertEquals((Float) layer.getTextLetterSpacing().getValue(), (Float) 0.3f);
}
@Test
- public void testTextJustify() {
+ public void testTextLetterSpacingAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-letter-spacing");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textLetterSpacing(
+ zoom(
+ exponential(
+ stop(2, textLetterSpacing(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextLetterSpacing());
+ assertNotNull(layer.getTextLetterSpacing().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextLetterSpacing().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextLetterSpacing().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextLetterSpacing().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextLetterSpacing().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextJustifyAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-justify");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textJustify(TEXT_JUSTIFY_LEFT));
assertEquals((String) layer.getTextJustify().getValue(), (String) TEXT_JUSTIFY_LEFT);
}
@Test
- public void testTextAnchor() {
+ public void testTextJustifyAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-justify");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textJustify(
+ zoom(
+ interval(
+ stop(2, textJustify(TEXT_JUSTIFY_LEFT))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextJustify());
+ assertNotNull(layer.getTextJustify().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextJustify().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextJustify().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextJustify().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textAnchor(TEXT_ANCHOR_CENTER));
assertEquals((String) layer.getTextAnchor().getValue(), (String) TEXT_ANCHOR_CENTER);
}
@Test
- public void testTextMaxAngle() {
+ public void testTextAnchorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-anchor");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textAnchor(
+ zoom(
+ interval(
+ stop(2, textAnchor(TEXT_ANCHOR_CENTER))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextAnchor());
+ assertNotNull(layer.getTextAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextAnchor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextMaxAngleAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-max-angle");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textMaxAngle(0.3f));
assertEquals((Float) layer.getTextMaxAngle().getValue(), (Float) 0.3f);
}
@Test
- public void testTextRotate() {
+ public void testTextMaxAngleAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-max-angle");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textMaxAngle(
+ zoom(
+ exponential(
+ stop(2, textMaxAngle(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextMaxAngle());
+ assertNotNull(layer.getTextMaxAngle().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextMaxAngle().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextMaxAngle().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextMaxAngle().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextMaxAngle().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextRotateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-rotate");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textRotate(0.3f));
assertEquals((Float) layer.getTextRotate().getValue(), (Float) 0.3f);
}
@Test
- public void testTextPadding() {
+ public void testTextRotateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-rotate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textRotate(
+ zoom(
+ exponential(
+ stop(2, textRotate(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextRotate());
+ assertNotNull(layer.getTextRotate().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextRotate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextRotate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextRotate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextRotate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextPaddingAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-padding");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textPadding(0.3f));
assertEquals((Float) layer.getTextPadding().getValue(), (Float) 0.3f);
}
@Test
- public void testTextKeepUpright() {
+ public void testTextPaddingAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-padding");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textPadding(
+ zoom(
+ exponential(
+ stop(2, textPadding(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextPadding());
+ assertNotNull(layer.getTextPadding().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextPadding().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextPadding().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextPadding().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextPadding().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextKeepUprightAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-keep-upright");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textKeepUpright(true));
assertEquals((Boolean) layer.getTextKeepUpright().getValue(), (Boolean) true);
}
@Test
- public void testTextTransform() {
+ public void testTextKeepUprightAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-keep-upright");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textKeepUpright(
+ zoom(
+ interval(
+ stop(2, textKeepUpright(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextKeepUpright());
+ assertNotNull(layer.getTextKeepUpright().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextKeepUpright().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextKeepUpright().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextKeepUpright().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextTransformAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-transform");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textTransform(TEXT_TRANSFORM_NONE));
assertEquals((String) layer.getTextTransform().getValue(), (String) TEXT_TRANSFORM_NONE);
}
@Test
- public void testTextOffset() {
+ public void testTextTransformAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-transform");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textTransform(
+ zoom(
+ interval(
+ stop(2, textTransform(TEXT_TRANSFORM_NONE))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextTransform());
+ assertNotNull(layer.getTextTransform().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextTransform().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextTransform().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextTransform().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextTransformAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-transform");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textTransform(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextTransform());
+ assertNotNull(layer.getTextTransform().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextTransform().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextTransform().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextTransform().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextTransformAsIntervalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-transform");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textTransform(
+ property(
+ "FeaturePropertyA",
+ interval(
+ stop(1, textTransform(TEXT_TRANSFORM_NONE))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextTransform());
+ assertNotNull(layer.getTextTransform().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextTransform().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextTransform().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.getTextTransform().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextOffsetAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-offset");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(textOffset(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getTextOffset().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(textOffset(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getTextOffset().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testTextAllowOverlap() {
+ public void testTextOffsetAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-offset");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textOffset(
+ zoom(
+ exponential(
+ stop(2, textOffset(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOffset());
+ assertNotNull(layer.getTextOffset().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextOffset().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextOffset().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextOffset().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextOffset().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextAllowOverlapAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-allow-overlap");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textAllowOverlap(true));
assertEquals((Boolean) layer.getTextAllowOverlap().getValue(), (Boolean) true);
}
@Test
- public void testTextIgnorePlacement() {
+ public void testTextAllowOverlapAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-allow-overlap");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textAllowOverlap(
+ zoom(
+ interval(
+ stop(2, textAllowOverlap(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextAllowOverlap());
+ assertNotNull(layer.getTextAllowOverlap().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextAllowOverlap().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextAllowOverlap().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextAllowOverlap().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextIgnorePlacementAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-ignore-placement");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textIgnorePlacement(true));
assertEquals((Boolean) layer.getTextIgnorePlacement().getValue(), (Boolean) true);
}
@Test
- public void testTextOptional() {
+ public void testTextIgnorePlacementAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-ignore-placement");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textIgnorePlacement(
+ zoom(
+ interval(
+ stop(2, textIgnorePlacement(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextIgnorePlacement());
+ assertNotNull(layer.getTextIgnorePlacement().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextIgnorePlacement().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextIgnorePlacement().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextIgnorePlacement().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextOptionalAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-optional");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textOptional(true));
assertEquals((Boolean) layer.getTextOptional().getValue(), (Boolean) true);
}
@Test
- public void testIconOpacity() {
+ public void testTextOptionalAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-optional");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textOptional(
+ zoom(
+ interval(
+ stop(2, textOptional(true))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOptional());
+ assertNotNull(layer.getTextOptional().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextOptional().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextOptional().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextOptional().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconOpacity(0.3f));
assertEquals((Float) layer.getIconOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testIconColor() {
+ public void testIconOpacityAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconOpacity(
+ zoom(
+ exponential(
+ stop(2, iconOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOpacity());
+ assertNotNull(layer.getIconOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconOpacity().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconOpacityAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOpacity());
+ assertNotNull(layer.getIconOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOpacity());
+ assertNotNull(layer.getIconOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOpacity());
+ assertNotNull(layer.getIconOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testIconOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconOpacity());
+ assertNotNull(layer.getIconOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testIconColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getIconColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testIconColorAsInt() {
+ public void testIconColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconColor(
+ zoom(
+ exponential(
+ stop(2, iconColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconColor());
+ assertNotNull(layer.getIconColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(iconColor(Color.RED));
- assertEquals(layer.getIconColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ iconColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconColor());
+ assertNotNull(layer.getIconColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconColor().getFunction().getStops().getClass());
}
@Test
- public void testIconHaloColor() {
+ public void testIconColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, iconColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconColor());
+ assertNotNull(layer.getIconColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", iconColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconColor());
+ assertNotNull(layer.getIconColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(iconColor(Color.RED));
+ assertEquals(layer.getIconColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testIconHaloColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconHaloColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getIconHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testIconHaloColorAsInt() {
+ public void testIconHaloColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconHaloColor(
+ zoom(
+ exponential(
+ stop(2, iconHaloColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloColor());
+ assertNotNull(layer.getIconHaloColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconHaloColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconHaloColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconHaloColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconHaloColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(iconHaloColor(Color.RED));
- assertEquals(layer.getIconHaloColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ iconHaloColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloColor());
+ assertNotNull(layer.getIconHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
}
@Test
- public void testIconHaloWidth() {
+ public void testIconHaloColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconHaloColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, iconHaloColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloColor());
+ assertNotNull(layer.getIconHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconHaloColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", iconHaloColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloColor());
+ assertNotNull(layer.getIconHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconHaloColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconHaloColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(iconHaloColor(Color.RED));
+ assertEquals(layer.getIconHaloColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testIconHaloWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconHaloWidth(0.3f));
assertEquals((Float) layer.getIconHaloWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testIconHaloBlur() {
+ public void testIconHaloWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconHaloWidth(
+ zoom(
+ exponential(
+ stop(2, iconHaloWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloWidth());
+ assertNotNull(layer.getIconHaloWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconHaloWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconHaloWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconHaloWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconHaloWidthAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloWidth(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloWidth());
+ assertNotNull(layer.getIconHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconHaloWidthAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloWidth(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconHaloWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloWidth());
+ assertNotNull(layer.getIconHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconHaloWidthAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloWidth(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconHaloWidth(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloWidth());
+ assertNotNull(layer.getIconHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloWidth().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconHaloWidth().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testIconHaloWidthAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloWidth(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconHaloWidth(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloWidth());
+ assertNotNull(layer.getIconHaloWidth().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconHaloWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconHaloWidth().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconHaloWidth().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconHaloWidth().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testIconHaloBlurAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-halo-blur");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconHaloBlur(0.3f));
assertEquals((Float) layer.getIconHaloBlur().getValue(), (Float) 0.3f);
}
@Test
- public void testIconTranslate() {
+ public void testIconHaloBlurAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-blur");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconHaloBlur(
+ zoom(
+ exponential(
+ stop(2, iconHaloBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloBlur());
+ assertNotNull(layer.getIconHaloBlur().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconHaloBlur().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconHaloBlur().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconHaloBlur().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconHaloBlurAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloBlur(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloBlur());
+ assertNotNull(layer.getIconHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconHaloBlurAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloBlur(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, iconHaloBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloBlur());
+ assertNotNull(layer.getIconHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testIconHaloBlurAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloBlur(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, iconHaloBlur(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloBlur());
+ assertNotNull(layer.getIconHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getIconHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getIconHaloBlur().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getIconHaloBlur().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testIconHaloBlurAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ iconHaloBlur(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, iconHaloBlur(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconHaloBlur());
+ assertNotNull(layer.getIconHaloBlur().getFunction());
+ assertEquals(CompositeFunction.class, layer.getIconHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getIconHaloBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getIconHaloBlur().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getIconHaloBlur().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getIconHaloBlur().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testIconTranslateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-translate");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(iconTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getIconTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(iconTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getIconTranslate().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testIconTranslateAnchor() {
+ public void testIconTranslateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-translate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconTranslate(
+ zoom(
+ exponential(
+ stop(2, iconTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconTranslate());
+ assertNotNull(layer.getIconTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getIconTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getIconTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getIconTranslate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testIconTranslateAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("icon-translate-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(iconTranslateAnchor(ICON_TRANSLATE_ANCHOR_MAP));
assertEquals((String) layer.getIconTranslateAnchor().getValue(), (String) ICON_TRANSLATE_ANCHOR_MAP);
}
@Test
- public void testTextOpacity() {
+ public void testIconTranslateAnchorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("icon-translate-anchor");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ iconTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, iconTranslateAnchor(ICON_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getIconTranslateAnchor());
+ assertNotNull(layer.getIconTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getIconTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getIconTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getIconTranslateAnchor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextOpacityAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-opacity");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textOpacity(0.3f));
assertEquals((Float) layer.getTextOpacity().getValue(), (Float) 0.3f);
}
@Test
- public void testTextColor() {
+ public void testTextOpacityAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-opacity");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textOpacity(
+ zoom(
+ exponential(
+ stop(2, textOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOpacity());
+ assertNotNull(layer.getTextOpacity().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextOpacity().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextOpacity().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextOpacity().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextOpacityAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOpacity(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOpacity());
+ assertNotNull(layer.getTextOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextOpacityAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOpacity(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textOpacity(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOpacity());
+ assertNotNull(layer.getTextOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextOpacityAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOpacity(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textOpacity(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOpacity());
+ assertNotNull(layer.getTextOpacity().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextOpacity().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextOpacity().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testTextOpacityAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-opacity");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textOpacity(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textOpacity(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextOpacity());
+ assertNotNull(layer.getTextOpacity().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextOpacity().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextOpacity().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextOpacity().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextOpacity().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextOpacity().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testTextColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getTextColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testTextColorAsInt() {
+ public void testTextColorAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textColor(
+ zoom(
+ exponential(
+ stop(2, textColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextColor());
+ assertNotNull(layer.getTextColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextColor().getFunction().getStops()).size());
+ }
+
+ @Test
+ public void testTextColorAsIdentitySourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextColor());
+ assertNotNull(layer.getTextColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextColorAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(textColor(Color.RED));
- assertEquals(layer.getTextColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ textColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, textColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextColor());
+ assertNotNull(layer.getTextColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextColor().getFunction().getStops().getClass());
}
@Test
- public void testTextHaloColor() {
+ public void testTextColorAsCategoricalSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", textColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextColor());
+ assertNotNull(layer.getTextColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(textColor(Color.RED));
+ assertEquals(layer.getTextColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTextHaloColorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-color");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textHaloColor("rgba(0, 0, 0, 1)"));
assertEquals((String) layer.getTextHaloColor().getValue(), (String) "rgba(0, 0, 0, 1)");
}
@Test
- public void testTextHaloColorAsInt() {
+ public void testTextHaloColorAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textHaloColor(
+ zoom(
+ exponential(
+ stop(2, textHaloColor("rgba(0, 0, 0, 1)"))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloColor());
+ assertNotNull(layer.getTextHaloColor().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextHaloColor().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextHaloColor().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextHaloColor().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextHaloColorAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-color");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(textHaloColor(Color.RED));
- assertEquals(layer.getTextHaloColorAsInt(), Color.RED);
+ // Set
+ layer.setProperties(
+ textHaloColor(property("FeaturePropertyA", Stops.<String>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloColor());
+ assertNotNull(layer.getTextHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
}
@Test
- public void testTextHaloWidth() {
+ public void testTextHaloColorAsExponentialSourceFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-color");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textHaloColor(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(Color.RED, textHaloColor(Color.RED))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloColor());
+ assertNotNull(layer.getTextHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextHaloColorAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-color");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloColor(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop("valueA", textHaloColor(Color.RED))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloColor());
+ assertNotNull(layer.getTextHaloColor().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloColor().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloColor().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextHaloColor().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextHaloColorAsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-color");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(textHaloColor(Color.RED));
+ assertEquals(layer.getTextHaloColorAsInt(), Color.RED);
+ }
+
+ @Test
+ public void testTextHaloWidthAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-width");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textHaloWidth(0.3f));
assertEquals((Float) layer.getTextHaloWidth().getValue(), (Float) 0.3f);
}
@Test
- public void testTextHaloBlur() {
+ public void testTextHaloWidthAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-width");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textHaloWidth(
+ zoom(
+ exponential(
+ stop(2, textHaloWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloWidth());
+ assertNotNull(layer.getTextHaloWidth().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextHaloWidth().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextHaloWidth().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextHaloWidth().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextHaloWidthAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloWidth(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloWidth());
+ assertNotNull(layer.getTextHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextHaloWidthAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloWidth(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textHaloWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloWidth());
+ assertNotNull(layer.getTextHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextHaloWidthAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloWidth(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textHaloWidth(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloWidth());
+ assertNotNull(layer.getTextHaloWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloWidth().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextHaloWidth().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testTextHaloWidthAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloWidth(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textHaloWidth(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloWidth());
+ assertNotNull(layer.getTextHaloWidth().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextHaloWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextHaloWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextHaloWidth().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextHaloWidth().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextHaloWidth().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testTextHaloBlurAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-halo-blur");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textHaloBlur(0.3f));
assertEquals((Float) layer.getTextHaloBlur().getValue(), (Float) 0.3f);
}
@Test
- public void testTextTranslate() {
+ public void testTextHaloBlurAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-blur");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textHaloBlur(
+ zoom(
+ exponential(
+ stop(2, textHaloBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloBlur());
+ assertNotNull(layer.getTextHaloBlur().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextHaloBlur().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextHaloBlur().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextHaloBlur().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextHaloBlurAsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloBlur(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloBlur());
+ assertNotNull(layer.getTextHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextHaloBlurAsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloBlur(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, textHaloBlur(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloBlur());
+ assertNotNull(layer.getTextHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testTextHaloBlurAsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloBlur(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, textHaloBlur(0.3f))
+ )
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloBlur());
+ assertNotNull(layer.getTextHaloBlur().getFunction());
+ assertEquals(SourceFunction.class, layer.getTextHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getTextHaloBlur().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
+ assertEquals(0.3f, ((SourceFunction) layer.getTextHaloBlur().getFunction()).getDefaultValue());
+ }
+
+ @Test
+ public void testTextHaloBlurAsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-halo-blur");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textHaloBlur(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, textHaloBlur(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(0.3f)
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextHaloBlur());
+ assertNotNull(layer.getTextHaloBlur().getFunction());
+ assertEquals(CompositeFunction.class, layer.getTextHaloBlur().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getTextHaloBlur().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getTextHaloBlur().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getTextHaloBlur().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getTextHaloBlur().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
+ public void testTextTranslateAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-translate");
assertNotNull(layer);
- //Set and Get
- layer.setProperties(textTranslate(new Float[] {0f, 0f}));
- assertEquals((Float[]) layer.getTextTranslate().getValue(), (Float[]) new Float[] {0f, 0f});
+ // Set and Get
+ layer.setProperties(textTranslate(new Float[]{0f,0f}));
+ assertEquals((Float[]) layer.getTextTranslate().getValue(), (Float[]) new Float[]{0f,0f});
}
@Test
- public void testTextTranslateAnchor() {
+ public void testTextTranslateAsCameraFunction() {
checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-translate");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Set
+ layer.setProperties(
+ textTranslate(
+ zoom(
+ exponential(
+ stop(2, textTranslate(new Float[]{0f,0f}))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextTranslate());
+ assertNotNull(layer.getTextTranslate().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextTranslate().getFunction().getClass());
+ assertEquals(ExponentialStops.class, layer.getTextTranslate().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.getTextTranslate().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.getTextTranslate().getFunction().getStops()).size());
+ }
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new SymbolLayer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ @Test
+ public void testTextTranslateAnchorAsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
Timber.i("text-translate-anchor");
assertNotNull(layer);
- //Set and Get
+ // Set and Get
layer.setProperties(textTranslateAnchor(TEXT_TRANSLATE_ANCHOR_MAP));
assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP);
}
+ @Test
+ public void testTextTranslateAnchorAsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("text-translate-anchor");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ textTranslateAnchor(
+ zoom(
+ interval(
+ stop(2, textTranslateAnchor(TEXT_TRANSLATE_ANCHOR_MAP))
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getTextTranslateAnchor());
+ assertNotNull(layer.getTextTranslateAnchor().getFunction());
+ assertEquals(CameraFunction.class, layer.getTextTranslateAnchor().getFunction().getClass());
+ assertEquals(IntervalStops.class, layer.getTextTranslateAnchor().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.getTextTranslateAnchor().getFunction().getStops()).size());
+ }
+
@After
public void unregisterIntentServiceIdlingResource() {
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 3b81b0805b..f1d68caa24 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
@@ -3,6 +3,7 @@
const properties = locals.properties;
-%>
// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`.
+
package com.mapbox.mapboxsdk.testapp.style;
import android.graphics.Color;
@@ -12,6 +13,15 @@ import android.support.test.runner.AndroidJUnit4;
import timber.log.Timber;
import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.style.functions.CompositeFunction;
+import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.functions.SourceFunction;
+import com.mapbox.mapboxsdk.style.functions.stops.CategoricalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IdentityStops;
+import com.mapbox.mapboxsdk.style.functions.stops.IntervalStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
import com.mapbox.mapboxsdk.style.layers.<%- camelize(type) %>Layer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity;
@@ -23,6 +33,9 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import static com.mapbox.mapboxsdk.style.functions.Function.*;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.*;
import static org.junit.Assert.*;
import static com.mapbox.mapboxsdk.style.layers.Property.*;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
@@ -33,112 +46,308 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.*;
@RunWith(AndroidJUnit4.class)
public class <%- camelize(type) %>LayerTest extends BaseStyleTest {
- @Rule
- public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+ @Rule
+ public final ActivityTestRule<RuntimeStyleTestActivity> rule = new ActivityTestRule<>(RuntimeStyleTestActivity.class);
+
+ private <%- camelize(type) %>Layer layer;
- private <%- camelize(type) %>Layer layer;
+ private OnMapReadyIdlingResource idlingResource;
- private OnMapReadyIdlingResource idlingResource;
+ private MapboxMap mapboxMap;
- private MapboxMap mapboxMap;
+ @Before
+ public void setup() {
+ idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
+ Espresso.registerIdlingResources(idlingResource);
+ mapboxMap = rule.getActivity().getMapboxMap();
- @Before
- public void setup() {
- idlingResource = new OnMapReadyIdlingResource(rule.getActivity());
- Espresso.registerIdlingResources(idlingResource);
+<% if (type === 'background') { -%>
+ Timber.i("Retrieving layer");
+ layer = mapboxMap.getLayerAs("background");
+<% } else { -%>
+ if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
+ Timber.i("Adding layer");
+ layer = new <%- camelize(type) %>Layer("my-layer", "composite");
+ layer.setSourceLayer("composite");
+ mapboxMap.addLayer(layer);
+ // Layer reference is now stale, get new reference
+ layer = mapboxMap.getLayerAs("my-layer");
}
+<% } -%>
+ }
- @Test
- public void testSetVisibility() {
- checkViewIsDisplayed(R.id.mapView);
+ @Test
+ public void testSetVisibility() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("Visibility");
+ assertNotNull(layer);
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Get initial
+ assertEquals(layer.getVisibility().getValue(), VISIBLE);
-<% if (type === 'background') { -%>
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
+ // Set
+ layer.setProperties(visibility(NONE));
+ assertEquals(layer.getVisibility().getValue(), NONE);
+ }
+
+<% for (const property of properties) { -%>
+ @Test
+ public void test<%- camelize(property.name) %>AsConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>));
+ assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>);
+ }
+<% if (supportsZoomFunction(property)) { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>AsCameraFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ zoom(
+<% if (property.function == 'piecewise-constant') { -%>
+ interval(
+ stop(2, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
+ )
<% } else { -%>
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new <%- camelize(type) %>Layer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ exponential(
+ stop(2, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
+ ).withBase(0.5f)
<% } -%>
- Timber.i("visibility");
- assertNotNull(layer);
+ )
+ )
+ );
- //Get initial
- assertEquals(layer.getVisibility().getValue(), VISIBLE);
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(CameraFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+<% if (property.function == 'piecewise-constant') { -%>
+ assertEquals(IntervalStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ assertEquals(1, ((IntervalStops) layer.get<%- camelize(property.name) %>().getFunction().getStops()).size());
+<% } else { -%>
+ assertEquals(ExponentialStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ assertEquals(0.5f, ((ExponentialStops) layer.get<%- camelize(property.name) %>().getFunction().getStops()).getBase(), 0.001);
+ assertEquals(1, ((ExponentialStops) layer.get<%- camelize(property.name) %>().getFunction().getStops()).size());
+<% } -%>
+ }
+<% } -%>
+<% if (supportsPropertyFunction(property)) { -%>
- //Set
- layer.setProperties(visibility(NONE));
- assertEquals(layer.getVisibility().getValue(), NONE);
- }
+ @Test
+ public void test<%- camelize(property.name) %>AsIdentitySourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
-<% for (const property of properties) { -%>
- @Test
- public void test<%- camelize(property.name) %>() {
- checkViewIsDisplayed(R.id.mapView);
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(property("FeaturePropertyA", Stops.<<%- propertyType(property) %>>identity()))
+ );
- mapboxMap = rule.getActivity().getMapboxMap();
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(SourceFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ }
+<% if (property.function == 'piecewise-constant') { -%>
-<% if (type === 'background') { -%>
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
+ @Test
+ public void test<%- camelize(property.name) %>AsIntervalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ property(
+ "FeaturePropertyA",
+ interval(
+<% if (property.type == 'color') { -%>
+ stop(Color.RED, <%- camelizeWithLeadingLowercase(property.name) %>(Color.RED))
+<% } else {-%>
+ stop(1, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
+ )
+<% } -%>
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(SourceFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ }
+<% } else if (property.type === 'array') { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>AsIntervalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ property(
+ "FeaturePropertyA",
+ interval(
+<% if (property.type == 'color') { -%>
+ stop(Color.RED, <%- camelizeWithLeadingLowercase(property.name) %>(Color.RED))
+<% } else {-%>
+ stop(1, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
+<% } -%>
+ )
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(SourceFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(IntervalStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ }
<% } else { -%>
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new <%- camelize(type) %>Layer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+
+ @Test
+ public void test<%- camelize(property.name) %>AsExponentialSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ property(
+ "FeaturePropertyA",
+ exponential(
+<% if (property.type == 'color') { -%>
+ stop(Color.RED, <%- camelizeWithLeadingLowercase(property.name) %>(Color.RED))
+<% } else {-%>
+ stop(<%- defaultValueJava(property) %>, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
<% } -%>
- Timber.i("<%- property.name %>");
- assertNotNull(layer);
+ ).withBase(0.5f)
+ )
+ )
+ );
- //Set and Get
- layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>));
- assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>);
- }
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(SourceFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void test<%- camelize(property.name) %>AsCategoricalSourceFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ property(
+ "FeaturePropertyA",
+ categorical(
<% if (property.type == 'color') { -%>
+ stop("valueA", <%- camelizeWithLeadingLowercase(property.name) %>(Color.RED))
+ )
+ )
+<% } else {-%>
+ stop(1.0f, <%- camelizeWithLeadingLowercase(property.name) %>(<%- defaultValueJava(property) %>))
+ )
+ ).withDefaultValue(<%- defaultValueJava(property) %>)
+<% } -%>
+ )
+ );
- @Test
- public void test<%- camelize(property.name) %>AsInt() {
- checkViewIsDisplayed(R.id.mapView);
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(SourceFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+<% if (property.type !== 'color') { -%>
+ assertEquals(<%- defaultValueJava(property) %>, ((SourceFunction) layer.get<%- camelize(property.name) %>().getFunction()).getDefaultValue());
+<% } -%>
+ }
+<% if (property.type !== 'color') { -%>
- mapboxMap = rule.getActivity().getMapboxMap();
+ @Test
+ public void test<%- camelize(property.name) %>AsCompositeFunction() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
-<% if (type === 'background') { -%>
- Timber.i("Retrieving layer");
- layer = mapboxMap.getLayerAs("background");
+ // Set
+ layer.setProperties(
+ <%- camelizeWithLeadingLowercase(property.name) %>(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, <%- camelizeWithLeadingLowercase(property.name) %>(0.9f))
+ ).withBase(0.5f)
+<% if (property.type == 'number') { -%>
+ ).withDefaultValue(<%- defaultValueJava(property) %>)
<% } else { -%>
- if ((layer = mapboxMap.getLayerAs("my-layer")) == null) {
- Timber.i("Adding layer");
- layer = new <%- camelize(type) %>Layer("my-layer", "composite");
- layer.setSourceLayer("composite");
- mapboxMap.addLayer(layer);
- //Layer reference is now stale, get new reference
- layer = mapboxMap.getLayerAs("my-layer");
- }
+ )
<% } -%>
- Timber.i("<%- property.name %>");
- assertNotNull(layer);
+ )
+ );
- //Set and Get
- layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(Color.RED));
- assertEquals(layer.get<%- camelize(property.name) %>AsInt(), Color.RED);
- }
+ // Verify
+ assertNotNull(layer.get<%- camelize(property.name) %>());
+ assertNotNull(layer.get<%- camelize(property.name) %>().getFunction());
+ assertEquals(CompositeFunction.class, layer.get<%- camelize(property.name) %>().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.get<%- camelize(property.name) %>().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.get<%- camelize(property.name) %>().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.get<%- camelize(property.name) %>().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, <%- propertyType(property) %>>, <%- propertyType(property) %>> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, <%- propertyType(property) %>>, <%- propertyType(property) %>>) layer.get<%- camelize(property.name) %>().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, <%- propertyType(property) %>>, <%- propertyType(property) %>> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+<% } -%>
+<% } -%>
+<% } -%>
+<% if (property.type == 'color') { -%>
+
+ @Test
+ public void test<%- camelize(property.name) %>AsIntConstant() {
+ checkViewIsDisplayed(R.id.mapView);
+ Timber.i("<%- property.name %>");
+ assertNotNull(layer);
+
+ // Set and Get
+ layer.setProperties(<%- camelizeWithLeadingLowercase(property.name) %>(Color.RED));
+ assertEquals(layer.get<%- camelize(property.name) %>AsInt(), Color.RED);
+ }
<% } -%>
<% } -%>
- @After
- public void unregisterIntentServiceIdlingResource() {
- Espresso.unregisterIdlingResources(idlingResource);
- }
+ @After
+ public void unregisterIntentServiceIdlingResource() {
+ Espresso.unregisterIdlingResources(idlingResource);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 684633bad1..9aeb0282b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -1,28 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.mapbox.mapboxsdk.testapp">
+ package="com.mapbox.mapboxsdk.testapp">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:name=".MapboxApplication"
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="@drawable/icon"
- android:roundIcon="@drawable/ic_launcher_round"
android:label="@string/app_name"
+ android:roundIcon="@drawable/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".activity.FeatureOverviewActivity"
- android:label="@string/app_name">
+ android:label="@string/app_name"
+ android:launchMode="singleTop">
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
@@ -31,7 +32,10 @@
android:label="@string/activity_info_window">
<meta-data
android:name="@string/category"
- android:value="@string/category_infowindow" />
+ android:value="@string/category_infowindow"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.infowindow.InfoWindowAdapterActivity"
@@ -39,7 +43,10 @@
android:label="@string/activity_infowindow_adapter">
<meta-data
android:name="@string/category"
- android:value="@string/category_infowindow" />
+ android:value="@string/category_infowindow"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.infowindow.DynamicInfoWindowAdapterActivity"
@@ -47,7 +54,10 @@
android:label="@string/activity_dynamic_infowindow_adapter">
<meta-data
android:name="@string/category"
- android:value="@string/category_infowindow" />
+ android:value="@string/category_infowindow"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.BulkMarkerActivity"
@@ -56,7 +66,10 @@
android:label="@string/activity_add_bulk_markers">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.AnimatedMarkerActivity"
@@ -64,7 +77,10 @@
android:label="@string/activity_animated_marker">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.DynamicMarkerChangeActivity"
@@ -72,7 +88,10 @@
android:label="@string/activity_dynamic_marker">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.PressForMarkerActivity"
@@ -80,7 +99,10 @@
android:label="@string/activity_press_for_marker">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.CameraAnimationTypeActivity"
@@ -88,7 +110,10 @@
android:label="@string/activity_camera_animation_types">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.CameraPositionActivity"
@@ -96,7 +121,10 @@
android:label="@string/activity_camera_position">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.LatLngBoundsActivity"
@@ -105,7 +133,10 @@
android:screenOrientation="portrait">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.fragment.MapFragmentActivity"
@@ -113,7 +144,10 @@
android:label="@string/activity_map_fragment">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_fragment"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.fragment.SupportMapFragmentActivity"
@@ -121,7 +155,10 @@
android:label="@string/activity_map_fragment_suport">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_fragment"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.fragment.MultiMapActivity"
@@ -129,7 +166,10 @@
android:label="@string/activity_multimap">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_fragment"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.ManualZoomActivity"
@@ -137,7 +177,10 @@
android:label="@string/activity_camera_zoom">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.MaxMinZoomActivity"
@@ -145,7 +188,10 @@
android:label="@string/activity_minmax_zoom">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.customlayer.CustomLayerActivity"
@@ -153,15 +199,22 @@
android:label="@string/activity_custom_layer">
<meta-data
android:name="@string/category"
- android:value="@string/category_custom_layer" />
+ android:value="@string/category_custom_layer"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.userlocation.MyLocationTrackingModeActivity"
android:description="@string/description_user_location_tracking"
- android:label="@string/activity_user_tracking_mode">
+ android:label="@string/activity_user_tracking_mode"
+ android:theme="@style/NoActionBar">
<meta-data
android:name="@string/category"
- android:value="@string/category_userlocation" />
+ android:value="@string/category_userlocation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.userlocation.MyLocationDrawableActivity"
@@ -169,7 +222,10 @@
android:label="@string/activity_user_tracking_customization">
<meta-data
android:name="@string/category"
- android:value="@string/category_userlocation" />
+ android:value="@string/category_userlocation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.userlocation.MyLocationTintActivity"
@@ -177,7 +233,10 @@
android:label="@string/activity_user_dot_color">
<meta-data
android:name="@string/category"
- android:value="@string/category_userlocation" />
+ android:value="@string/category_userlocation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.userlocation.MyLocationToggleActivity"
@@ -185,7 +244,10 @@
android:label="@string/activity_user_location_toggle">
<meta-data
android:name="@string/category"
- android:value="@string/category_userlocation" />
+ android:value="@string/category_userlocation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.PolygonActivity"
@@ -193,7 +255,10 @@
android:label="@string/activity_polygon">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.PolylineActivity"
@@ -201,31 +266,22 @@
android:label="@string/activity_polyline">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
- </activity>
- <activity
- android:name=".activity.directions.DirectionsActivity"
- android:description="@string/description_directions"
- android:label="@string/activity_directions">
+ android:value="@string/category_annotation"/>
<meta-data
- android:name="@string/category"
- android:value="@string/category_directions" />
- </activity>
- <activity
- android:name=".activity.geocoding.GeocoderActivity"
- android:description="@string/description_geocoder"
- android:label="@string/activity_geocoder">
- <meta-data
- android:name="@string/category"
- android:value="@string/category_geocoding" />
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.camera.ScrollByActivity"
android:description="@string/description_scroll_by"
- android:label="@string/activity_scroll_by">
+ android:label="@string/activity_scroll_by"
+ android:theme="@style/NoActionBar">
<meta-data
android:name="@string/category"
- android:value="@string/category_camera" />
+ android:value="@string/category_camera"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.MapPaddingActivity"
@@ -234,7 +290,10 @@
android:screenOrientation="portrait">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.DebugModeActivity"
@@ -242,7 +301,10 @@
android:label="@string/activity_debug_mode">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.offline.OfflineActivity"
@@ -250,7 +312,10 @@
android:label="@string/activity_offline">
<meta-data
android:name="@string/category"
- android:value="@string/category_offline" />
+ android:value="@string/category_offline"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.offline.UpdateMetadataActivity"
@@ -258,7 +323,21 @@
android:label="@string/activity_update_metadata">
<meta-data
android:name="@string/category"
- android:value="@string/category_offline" />
+ android:value="@string/category_offline"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
+ android:name=".activity.offline.DeleteRegionActivity"
+ android:description="@string/description_offline_region_delete"
+ android:label="@string/activity_offline_region_delete">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_offline"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.imagegenerator.SnapshotActivity"
@@ -266,7 +345,10 @@
android:label="@string/activity_snapshot">
<meta-data
android:name="@string/category"
- android:value="@string/category_imagegenerator" />
+ android:value="@string/category_imagegenerator"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.DoubleMapActivity"
@@ -274,7 +356,10 @@
android:label="@string/activity_double_map">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.MarkerViewActivity"
@@ -282,23 +367,10 @@
android:label="@string/activity_view_marker">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
- </activity>
- <activity
- android:name=".activity.annotation.MarkerViewScaleActivity"
- android:description="@string/description_view_marker_scale"
- android:label="@string/activity_view_marker_scale">
+ android:value="@string/category_annotation"/>
<meta-data
- android:name="@string/category"
- android:value="@string/category_annotation" />
- </activity>
- <activity
- android:name=".activity.navigation.LocationPickerActivity"
- android:description="@string/description_location_picker"
- android:label="@string/activity_location_picker">
- <meta-data
- android:name="@string/category"
- android:value="@string/category_navigation" />
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.fragment.ViewPagerActivity"
@@ -306,7 +378,10 @@
android:label="@string/activity_viewpager">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_fragment"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.NavigationDrawerActivity"
@@ -315,7 +390,10 @@
android:theme="@style/AppTheme.ActionBar.Transparent">
<meta-data
android:name="@string/category"
- android:value="@string/category_fragment" />
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.SimpleMapActivity"
@@ -323,7 +401,10 @@
android:label="@string/activity_simple_map">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_basic"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.RuntimeStyleActivity"
@@ -331,7 +412,21 @@
android:label="@string/activity_runtime_style">
<meta-data
android:name="@string/category"
- android:value="@string/category_style" />
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
+ android:name=".activity.style.DataDrivenStyleActivity"
+ android:description="@string/description_data_driven_style"
+ android:label="@string/activity_data_driven_style">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.CircleLayerActivity"
@@ -340,6 +435,20 @@
<meta-data
android:name="@string/category"
android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
+ <activity
+ android:name=".activity.style.SymbolLayerActivity"
+ android:description="@string/description_symbol_layer"
+ android:label="@string/activity_symbol_layer">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.GeoJsonClusteringActivity"
@@ -347,14 +456,21 @@
android:label="@string/activity_geojson_clustering">
<meta-data
android:name="@string/category"
- android:value="@string/category_style" />
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
- <activity android:name=".activity.style.RealTimeGeoJsonActivity"
+ <activity
+ android:name=".activity.style.RealTimeGeoJsonActivity"
android:description="@string/description_geojson_realtime"
android:label="@string/activity_geojson_realtime">
<meta-data
android:name="@string/category"
- android:value="@string/category_style" />
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.StyleFileActivity"
@@ -362,7 +478,10 @@
android:label="@string/activity_style_file">
<meta-data
android:name="@string/category"
- android:value="@string/category_style" />
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.style.CustomSpriteActivity"
@@ -370,7 +489,10 @@
android:label="@string/activity_add_sprite">
<meta-data
android:name="@string/category"
- android:value="@string/category_style" />
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.imagegenerator.PrintActivity"
@@ -378,7 +500,10 @@
android:label="@string/activity_print">
<meta-data
android:name="@string/category"
- android:value="@string/category_imagegenerator" />
+ android:value="@string/category_imagegenerator"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<!-- Features -->
@@ -388,7 +513,10 @@
android:label="@string/activity_query_rendered_feature_properties">
<meta-data
android:name="@string/category"
- android:value="@string/category_features" />
+ android:value="@string/category_features"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.feature.QueryRenderedFeaturesBoxCountActivity"
@@ -396,7 +524,10 @@
android:label="@string/activity_query_rendered_features_box_count">
<meta-data
android:name="@string/category"
- android:value="@string/category_features" />
+ android:value="@string/category_features"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.feature.QueryRenderedFeaturesBoxSymbolCountActivity"
@@ -404,7 +535,10 @@
android:label="@string/activity_query_rendered_features_box_symbol_count">
<meta-data
android:name="@string/category"
- android:value="@string/category_features" />
+ android:value="@string/category_features"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.feature.QueryRenderedFeaturesBoxHighlightActivity"
@@ -412,15 +546,10 @@
android:label="@string/activity_query_rendered_features_box_highlight">
<meta-data
android:name="@string/category"
- android:value="@string/category_features" />
- </activity>
- <activity
- android:name=".activity.navigation.CarDrivingActivity"
- android:description="@string/description_car_driving"
- android:label="@string/activity_car_driving">
+ android:value="@string/category_features"/>
<meta-data
- android:name="@string/category"
- android:value="@string/category_navigation" />
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.AddRemoveMarkerActivity"
@@ -428,7 +557,10 @@
android:label="@string/activity_add_remove_markers">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.maplayout.MapInDialogActivity"
@@ -436,7 +568,10 @@
android:label="@string/activity_map_in_dialog">
<meta-data
android:name="@string/category"
- android:value="@string/category_maplayout" />
+ android:value="@string/category_maplayout"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<activity
android:name=".activity.annotation.MarkerViewsInRectangleActivity"
@@ -444,28 +579,35 @@
android:label="@string/activity_marker_view_rectangle">
<meta-data
android:name="@string/category"
- android:value="@string/category_annotation" />
+ android:value="@string/category_annotation"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
</activity>
<!-- For Instrumentation tests -->
- <activity android:name=".activity.style.RuntimeStyleTestActivity" />
- <activity android:name=".activity.style.RuntimeStyleTimingTestActivity" />
- <activity android:name=".activity.espresso.EspressoTestActivity" />
+ <activity
+ android:name=".activity.style.RuntimeStyleTestActivity"
+ android:screenOrientation="portrait"/>
+ <activity android:name=".activity.style.RuntimeStyleTimingTestActivity"
+ android:screenOrientation="portrait"/>
+ <activity android:name=".activity.espresso.EspressoTestActivity"
+ android:screenOrientation="portrait"/>
<!-- Configuration Settings -->
<meta-data
android:name="com.mapbox.TestEventsServer"
- android:value="https://cloudfront-staging.tilestream.net" />
+ android:value="https://cloudfront-staging.tilestream.net"/>
<meta-data
android:name="com.mapbox.TestEventsAccessToken"
- android:value="pk.eyJ1IjoiYmxzdGFnaW5nIiwiYSI6ImNpdDF3OHpoaTAwMDcyeXA5Y3Z0Nmk2dzEifQ.0IfB7v5Qbm2MGVYt8Kb8fg" />
+ android:value="pk.eyJ1IjoiYmxzdGFnaW5nIiwiYSI6ImNpdDF3OHpoaTAwMDcyeXA5Y3Z0Nmk2dzEifQ.0IfB7v5Qbm2MGVYt8Kb8fg"/>
<!-- Comment out this setting to switch to external storage (and disable internal) in your app -->
<!-- <meta-data -->
<!-- android:name="com.mapbox.SetStorageExternal" -->
<!-- android:value="true" /> -->
- <service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService" />
+ <service android:name="com.mapbox.services.android.telemetry.service.TelemetryService"/>
</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 a10c6eaad3..e344343627 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
@@ -10,6 +10,12 @@ import timber.log.Timber;
import static timber.log.Timber.DebugTree;
+/**
+ * Application class of the test application.
+ * <p>
+ * Initialises components as LeakCanary, Strictmode, Timber and Mapbox
+ * </p>
+ */
public class MapboxApplication extends Application {
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
index 9ba51e2694..e8e1c17816 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/FeatureOverviewActivity.java
@@ -14,14 +14,9 @@ import android.support.annotation.StringRes;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
import android.view.View;
import com.mapbox.mapboxsdk.testapp.R;
@@ -35,6 +30,15 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import timber.log.Timber;
+
+/**
+ * Activity shown when application is started
+ * <p>
+ * This activity will generate data for RecyclerView based on the AndroidManifest entries.
+ * It uses tags as category and description to order the different entries.
+ * </p>
+ */
public class FeatureOverviewActivity extends AppCompatActivity {
private static final String KEY_STATE_FEATURES = "featureList";
@@ -46,16 +50,7 @@ public class FeatureOverviewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- toolbar.setTitle(getString(R.string.app_name));
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setElevation(getResources().getDimension(R.dimen.toolbar_shadow));
- }
+ setContentView(R.layout.activity_feature_overview);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
@@ -218,8 +213,6 @@ public class FeatureOverviewActivity extends AppCompatActivity {
List<String> requiresPermissionActvities = new ArrayList<String>() {
{
add(resources.getString(R.string.activity_double_map));
- add(getString(R.string.activity_location_picker));
- add(getString(R.string.activity_car_driving));
}
};
@@ -232,4 +225,4 @@ public class FeatureOverviewActivity extends AppCompatActivity {
onFeaturesLoaded(features);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AddRemoveMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AddRemoveMarkerActivity.java
index 6c56aa4a7a..abadc3e5d9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AddRemoveMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AddRemoveMarkerActivity.java
@@ -1,16 +1,10 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
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.camera.CameraPosition;
@@ -20,7 +14,13 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
+import timber.log.Timber;
+
+/**
+ * Test activity showcasing updating a Marker image when changing zoom levels
+ */
public class AddRemoveMarkerActivity extends AppCompatActivity {
public static final double THRESHOLD = 5.0;
@@ -40,24 +40,20 @@ public class AddRemoveMarkerActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_remove_marker);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
+ // ShapeDrawable to Icon
+ final Icon shapeDrawableIcon = IconUtils.drawableToIcon(this, R.drawable.ic_circle,
+ ContextCompat.getColor(this, R.color.redAccent));
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- final Icon icon1 = IconFactory.getInstance(this).fromResource(R.drawable.ic_arsenal);
- final Icon icon2 = IconFactory.getInstance(this).fromResource(R.drawable.ic_chelsea);
+ // VectorDrawable to Icon
+ final Icon vectorDrawableIcon = IconUtils.drawableToIcon(this, R.drawable.ic_layers,
+ ContextCompat.getColor(this, R.color.blueAccent));
lowThresholdMarker = new MarkerOptions()
- .icon(icon1)
+ .icon(shapeDrawableIcon)
.position(new LatLng(-0.1, 0));
highThresholdMarker = new MarkerOptions()
- .icon(icon2)
+ .icon(vectorDrawableIcon)
.position(new LatLng(0.1, 0));
mapView = (MapView) findViewById(R.id.mapView);
@@ -170,14 +166,4 @@ public class AddRemoveMarkerActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-} \ No newline at end of file
+}
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
index 50e6c44b6e..52181cee0c 100644
--- 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
@@ -8,10 +8,9 @@ import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
+import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.mapbox.mapboxsdk.annotations.Icon;
@@ -27,11 +26,17 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.services.commons.models.Position;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
import com.mapbox.services.api.utils.turf.TurfMeasurement;
+import com.mapbox.services.commons.models.Position;
+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;
@@ -42,20 +47,16 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
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);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -64,7 +65,8 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
AnimatedMarkerActivity.this.mapboxMap = mapboxMap;
setupMap();
- mapView.post(new Runnable() {
+
+ animationRunnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
@@ -73,7 +75,8 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
addPassenger();
addMainCar();
}
- });
+ };
+ mapView.post(animationRunnable);
}
});
}
@@ -87,11 +90,15 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
}
private void addPassenger() {
+ if (isActivityStopped()) {
+ return;
+ }
+
LatLng randomLatLng = getLatLngInBounds();
if (passengerMarker == null) {
- Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
- .fromResource(R.drawable.ic_directions_run_black_24dp);
+ 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));
@@ -101,6 +108,10 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
}
private void addMainCar() {
+ if (isActivityStopped()) {
+ return;
+ }
+
LatLng randomLatLng = getLatLngInBounds();
if (carMarker == null) {
@@ -113,13 +124,17 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
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
@@ -131,18 +146,23 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
}
protected void addRandomCar() {
- createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top, new MarkerViewManager.OnMarkerViewAddedListener() {
- @Override
- public void onViewAdded(@NonNull MarkerView markerView) {
- randomlyMoveMarker(markerView);
- }
- });
+ markerViews.add(createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top,
+ new MarkerViewManager.OnMarkerViewAddedListener() {
+ @Override
+ public void onViewAdded(@NonNull MarkerView markerView) {
+ randomlyMoveMarker(markerView);
+ }
+ }));
}
private void randomlyMoveMarker(final MarkerView marker) {
+ if (isActivityStopped()) {
+ return;
+ }
+
ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds());
- //Add listener to restart animation on end
+ // Add listener to restart animation on end
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -170,12 +190,12 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
.fromResource(carResource);
- //View Markers
+ // View Markers
return mapboxMap.addMarker(new MarkerViewOptions()
.position(start)
.icon(icon), listener);
- //GL Markers
+ // GL Markers
// return mapboxMap.addMarker(new MarkerOptions()
// .position(start)
// .icon(icon));
@@ -193,17 +213,6 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
protected void onStart() {
super.onStart();
mapView.onStart();
@@ -224,7 +233,21 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
@Override
protected void onStop() {
super.onStop();
+
+ stopped = true;
+
+ // Stop ongoing animations, prevent memory lekas
+ 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
@@ -268,4 +291,8 @@ public class AnimatedMarkerActivity extends AppCompatActivity {
Position.fromCoordinates(to.getLongitude(), to.getLatitude())
);
}
+
+ private boolean isActivityStopped() {
+ return stopped;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
index 0d97289e56..8b238e49a8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/BulkMarkerActivity.java
@@ -3,19 +3,13 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.app.ProgressDialog;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.ActionBar;
+import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
+import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
@@ -25,7 +19,6 @@ import android.widget.TextView;
import android.widget.Toast;
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.annotations.MarkerViewOptions;
@@ -35,6 +28,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
import org.json.JSONException;
@@ -42,8 +36,14 @@ import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Random;
+import timber.log.Timber;
+
+/**
+ * Test activity showcasing adding a large amount of Markers or MarkerViews.
+ */
public class BulkMarkerActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private MapboxMap mapboxMap;
@@ -56,31 +56,12 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marker_bulk);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayShowTitleEnabled(false);
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
BulkMarkerActivity.this.mapboxMap = mapboxMap;
-
- if (actionBar != null) {
- ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(
- actionBar.getThemedContext(), R.array.bulk_marker_list, android.R.layout.simple_spinner_item);
- spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- Spinner spinner = (Spinner) findViewById(R.id.spinner);
- spinner.setAdapter(spinnerAdapter);
- spinner.setOnItemSelectedListener(BulkMarkerActivity.this);
- }
}
});
@@ -91,6 +72,19 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
}
@Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(
+ this, R.array.bulk_marker_list, android.R.layout.simple_spinner_item);
+ spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ getMenuInflater().inflate(R.menu.menu_bulk_marker, menu);
+ MenuItem item = menu.findItem(R.id.spinner);
+ Spinner spinner = (Spinner) MenuItemCompat.getActionView(item);
+ spinner.setAdapter(spinnerAdapter);
+ spinner.setOnItemSelectedListener(BulkMarkerActivity.this);
+ return true;
+ }
+
+ @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int amount = Integer.valueOf(getResources().getStringArray(R.array.bulk_marker_list)[position]);
if (locations == null) {
@@ -124,11 +118,8 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
Random random = new Random();
int randomIndex;
- Drawable drawable = ContextCompat.getDrawable(BulkMarkerActivity.this, R.drawable.ic_droppin_24dp);
-
- int redColor = ResourcesCompat.getColor(getResources(), android.R.color.holo_red_dark, getTheme());
- drawable.setColorFilter(redColor, PorterDuff.Mode.SRC_IN);
- Icon icon = IconFactory.getInstance(this).fromDrawable(drawable);
+ int color = ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme());
+ Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_droppin, color);
List<MarkerViewOptions> markerOptionsList = new ArrayList<>();
for (int i = 0; i < amount; i++) {
@@ -209,18 +200,10 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
mapView.onLowMemory();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
private class FabClickListener implements View.OnClickListener {
+
+ private TextView viewCountView;
+
@Override
public void onClick(final View view) {
if (mapboxMap != null) {
@@ -243,13 +226,15 @@ public class BulkMarkerActivity extends AppCompatActivity implements AdapterView
showMarkers(amount);
}
+ viewCountView = (TextView) findViewById(R.id.countView);
+
mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(@MapView.MapChange int change) {
if (change == MapView.REGION_IS_CHANGING || change == MapView.REGION_DID_CHANGE) {
if (!mapboxMap.getMarkerViewManager().getMarkerViewAdapters().isEmpty()) {
- TextView viewCountView = (TextView) findViewById(R.id.countView);
- viewCountView.setText("ViewCache size " + (mapView.getChildCount() - 5));
+ viewCountView.setText(String.format(Locale.getDefault(), "ViewCache size %d",
+ mapboxMap.getMarkerViewManager().getMarkerViewContainer().getChildCount()));
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
index 8446329e43..f7ffc61a7d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/DynamicMarkerChangeActivity.java
@@ -4,13 +4,10 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -18,7 +15,11 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
+/**
+ * Test activity showcasing updating a Marker position, title, icon and snippet.
+ */
public class DynamicMarkerChangeActivity extends AppCompatActivity {
private static final LatLng LAT_LNG_CHELSEA = new LatLng(51.481670, -0.190849);
@@ -26,7 +27,6 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
- private IconFactory iconFactory;
private Marker marker;
@Override
@@ -34,17 +34,6 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic_marker);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- iconFactory = IconFactory.getInstance(this);
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.setTag(false);
mapView.onCreate(savedInstanceState);
@@ -55,7 +44,8 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
// Create marker
MarkerOptions markerOptions = new MarkerOptions()
.position(LAT_LNG_CHELSEA)
- .icon(iconFactory.fromResource(R.drawable.ic_chelsea))
+ .icon(IconUtils.drawableToIcon(DynamicMarkerChangeActivity.this, R.drawable.ic_stars,
+ ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())))
.title(getString(R.string.dynamic_marker_chelsea_title))
.snippet(getString(R.string.dynamic_marker_chelsea_snippet));
marker = mapboxMap.addMarker(markerOptions);
@@ -81,7 +71,11 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
// update marker
marker.setPosition(first ? LAT_LNG_CHELSEA : LAT_LNG_ARSENAL);
- marker.setIcon(iconFactory.fromResource(first ? R.drawable.ic_chelsea : R.drawable.ic_arsenal));
+ marker.setIcon(IconUtils.drawableToIcon(this, R.drawable.ic_stars, first
+ ? ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme()) :
+ ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())
+ ));
+
marker.setTitle(first
? getString(R.string.dynamic_marker_chelsea_title) : getString(R.string.dynamic_marker_arsenal_title));
marker.setSnippet(first
@@ -129,15 +123,4 @@ public class DynamicMarkerChangeActivity extends AppCompatActivity {
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
index f1dc7f8c0d..f2f82865d1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java
@@ -3,17 +3,16 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
+import android.animation.FloatEvaluator;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -39,6 +38,13 @@ import com.mapbox.mapboxsdk.testapp.model.annotations.TextMarkerViewOptions;
import java.util.Random;
+/**
+ * Test activity showcasing multiple MarkerViews above Washington D.C.
+ * <p>
+ * Shows a couple of open InfoWindows out of current Viewport.
+ * Updates the rotation and location of a couple of MarkerViews.
+ * </p>
+ */
public class MarkerViewActivity extends AppCompatActivity {
private static final LatLng[] LAT_LNGS = new LatLng[] {
@@ -47,7 +53,7 @@ public class MarkerViewActivity extends AppCompatActivity {
new LatLng(38.907227, -77.036530),
new LatLng(38.905607, -77.031916),
new LatLng(38.889441, -77.050134),
- new LatLng(38.888000, -77.050000) //Slight overlap to show re-ordering on selection
+ new LatLng(38.888000, -77.050000) // Slight overlap to show re-ordering on selection
};
private MapboxMap mapboxMap;
@@ -71,15 +77,6 @@ public class MarkerViewActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marker_view);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
final TextView viewCountView = (TextView) findViewById(R.id.countView);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
@@ -110,7 +107,12 @@ public class MarkerViewActivity extends AppCompatActivity {
options.title("Hello");
options.position(new LatLng(38.899774, -77.023237));
options.flat(true);
- mapboxMap.addMarker(options);
+ MarkerView markerView = mapboxMap.addMarker(options);
+
+ // Use object animator to rotate MarkerView
+ ValueAnimator markerAnimator = ObjectAnimator.ofObject(markerView, "rotation", new FloatEvaluator(), -90, 90);
+ markerAnimator.setDuration(5000);
+ markerAnimator.start();
MarkerViewActivity.this.mapboxMap.addMarker(new MarkerOptions()
.title("United States")
@@ -168,13 +170,13 @@ public class MarkerViewActivity extends AppCompatActivity {
movingMarkerOne = MarkerViewActivity.this.mapboxMap.addMarker(new MarkerViewOptions()
.position(CarLocation.CAR_0_LNGS[0])
.icon(IconFactory.getInstance(mapView.getContext())
- .fromResource(R.drawable.ic_chelsea))
+ .fromResource(R.drawable.ic_android))
);
movingMarkerTwo = mapboxMap.addMarker(new MarkerViewOptions()
.position(CarLocation.CAR_1_LNGS[0])
.icon(IconFactory.getInstance(mapView.getContext())
- .fromResource(R.drawable.ic_arsenal))
+ .fromResource(R.drawable.ic_android_2))
);
// allow more open infowindows at the same time
@@ -458,17 +460,6 @@ public class MarkerViewActivity extends AppCompatActivity {
mapView.onLowMemory();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
private static class CarLocation {
static LatLng[] CAR_0_LNGS = new LatLng[] {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java
deleted file mode 100644
index 53e352c2e6..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewScaleActivity.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.annotation;
-
-import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
-import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.testapp.R;
-
-import java.util.Locale;
-
-public class MarkerViewScaleActivity extends AppCompatActivity implements OnMapReadyCallback {
-
- private MapboxMap mapboxMap;
- private MapView mapView;
-
- private MarkerView markerView;
- private MarkerViewManager markerViewManager;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_marker_view_scale);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(this);
- }
-
- @Override
- public void onMapReady(MapboxMap map) {
- mapboxMap = map;
- markerViewManager = map.getMarkerViewManager();
-
- final SeekBar xBar = (SeekBar) findViewById(R.id.seekbar_factor);
- final TextView textView = (TextView) findViewById(R.id.textview_factor);
-
- // We need to listen to a render event to be sure
- // the View of the Marker has been added to the map
- mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
- @Override
- public void onMapChanged(@MapView.MapChange int change) {
- if (isMarkerRendered()) {
- Toast.makeText(MarkerViewScaleActivity.this, "MarkerView is ready", Toast.LENGTH_SHORT).show();
- View view = markerViewManager.getView(markerView);
- xBar.setOnSeekBarChangeListener(new FactorChangeListener(view, textView));
- xBar.setClickable(true);
- mapView.removeOnMapChangedListener(this);
- }
- }
-
- private boolean isMarkerRendered() {
- return markerView != null && markerViewManager.getView(markerView) != null;
- }
- });
-
- Icon icon = IconFactory.getInstance(MarkerViewScaleActivity.this)
- .fromResource(R.drawable.ic_circle);
-
- markerView = mapboxMap.addMarker(new MarkerViewOptions()
- .position(new LatLng(38.907192, -77.036871))
- .icon(icon)
- .flat(true));
- }
-
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- mapView.onResume();
- }
-
- @Override
- public void onStart() {
- super.onResume();
- mapView.onStart();
- }
-
- @Override
- public void onStop() {
- super.onStop();
- mapView.onStop();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- mapView.onPause();
- }
-
- @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();
- }
-
- private static class FactorChangeListener implements SeekBar.OnSeekBarChangeListener {
-
- private TextView textView;
- private View view;
-
- FactorChangeListener(View view, TextView textView) {
- this.view = view;
- this.textView = textView;
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- float newScale = getScale(progress);
- textView.setText(String.format(Locale.US, "Scale: %.1f", newScale));
- if (view != null) {
- view.setScaleX(newScale);
- view.setScaleY(newScale);
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // Not used
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // Not used
- }
-
- private float getScale(int progress) {
- float scale = 1.0f * progress / 25;
- return scale < 1.0 ? 1.0f : scale;
- }
- }
-
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewsInRectangleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewsInRectangleActivity.java
index 99a0465092..266db3fdd1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewsInRectangleActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewsInRectangleActivity.java
@@ -2,10 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.graphics.RectF;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -33,11 +30,10 @@ public class MarkerViewsInRectangleActivity extends AppCompatActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marker_view_in_rect);
- setupActionBar();
selectionBox = findViewById(R.id.selection_box);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -53,14 +49,14 @@ public class MarkerViewsInRectangleActivity extends AppCompatActivity implements
@Override
public void onClick(View view) {
- //Query
+ // Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i(String.format("Querying box %s", box));
List<MarkerView> markers = mapboxMap.getMarkerViewsInRect(box);
- //Show count
+ // Show count
Toast.makeText(
MarkerViewsInRectangleActivity.this,
String.format("%s markers inside box", markers.size()),
@@ -108,26 +104,4 @@ public class MarkerViewsInRectangleActivity extends AppCompatActivity implements
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
index 16efa9f190..a2245a28e0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolygonActivity.java
@@ -5,7 +5,6 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.ViewGroup;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
@@ -17,7 +16,6 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.utils.ToolbarComposer;
import java.util.ArrayList;
import java.util.List;
@@ -31,9 +29,9 @@ import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.C
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.STAR_SHAPE_POINTS;
/**
- * Activity to test the Polygon annotation API & programmatically creating a MapView.
+ * Test activity to showcase the Polygon annotation API & programmatically creating a MapView.
* <p>
- * Showcases changing Polygon features as visibility, alpha, color and points.
+ * Shows how to change Polygon features as visibility, alpha, color and points.
* </p>
*/
public class PolygonActivity extends AppCompatActivity implements OnMapReadyCallback {
@@ -50,8 +48,6 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_polygon);
- ToolbarComposer.initDefaultUpToolbar(this, R.id.toolbar);
// configure inital map state
MapboxMapOptions options = new MapboxMapOptions()
@@ -72,11 +68,7 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
- // add to layout
- ViewGroup container = (ViewGroup) findViewById(R.id.container);
- if (container != null) {
- container.addView(mapView);
- }
+ setContentView(mapView);
}
@Override
@@ -132,25 +124,18 @@ public class PolygonActivity extends AppCompatActivity implements OnMapReadyCall
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
-
case R.id.action_id_alpha:
fullAlpha = !fullAlpha;
polygon.setAlpha(fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA);
return true;
-
case R.id.action_id_visible:
visible = !visible;
polygon.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
return true;
-
case R.id.action_id_points:
allPoints = !allPoints;
polygon.setPoints(allPoints ? STAR_SHAPE_POINTS : BROKEN_SHAPE_POINTS);
return true;
-
case R.id.action_id_color:
color = !color;
polygon.setFillColor(color ? BLUE_COLOR : RED_COLOR);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
index 44f11ca674..0aaa6127f4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PolylineActivity.java
@@ -3,12 +3,11 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.widget.Toast;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
@@ -22,6 +21,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+/**
+ * Test activity showcasing the Polyline annotations API.
+ * <p>
+ * Shows how to add and remove polylines.
+ * </p>
+ */
public class PolylineActivity extends AppCompatActivity {
private static final String STATE_POLYLINE_OPTIONS = "polylineOptions";
@@ -52,15 +57,6 @@ public class PolylineActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_polyline);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
if (savedInstanceState != null) {
polylineOptions = savedInstanceState.getParcelableArrayList(STATE_POLYLINE_OPTIONS);
} else {
@@ -182,11 +178,16 @@ public class PolylineActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
+ if (polylines.size() <= 0) {
+ Toast.makeText(PolylineActivity.this, "No polylines on map", Toast.LENGTH_LONG).show();
+ return super.onOptionsItemSelected(item);
+ }
switch (item.getItemId()) {
case R.id.action_id_remove:
// test to remove all annotations
polylineOptions.clear();
mapboxMap.clear();
+ polylines.clear();
return true;
case R.id.action_id_alpha:
@@ -216,11 +217,6 @@ public class PolylineActivity extends AppCompatActivity {
p.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
}
return true;
-
- case android.R.id.home:
- onBackPressed();
- return true;
-
default:
return super.onOptionsItemSelected(item);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
index 4b23060eec..7cfe35f160 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/PressForMarkerActivity.java
@@ -4,9 +4,7 @@ import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
@@ -20,6 +18,12 @@ import com.mapbox.mapboxsdk.testapp.R;
import java.text.DecimalFormat;
import java.util.ArrayList;
+/**
+ * Test activity showcasing to add a Marker on click.
+ * <p>
+ * Shows how to use a OnMapClickListener and a OnMapLongClickListener
+ * </p>
+ */
public class PressForMarkerActivity extends AppCompatActivity {
private MapView mapView;
@@ -35,15 +39,6 @@ public class PressForMarkerActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_press_for_marker);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -55,19 +50,14 @@ public class PressForMarkerActivity extends AppCompatActivity {
mapboxMap.setOnMapLongClickListener(new MapboxMap.OnMapLongClickListener() {
@Override
public void onMapLongClick(@NonNull LatLng point) {
- final PointF pixel = mapboxMap.getProjection().toScreenLocation(point);
-
- String title = LAT_LON_FORMATTER.format(point.getLatitude()) + ", "
- + LAT_LON_FORMATTER.format(point.getLongitude());
- String snippet = "X = " + (int) pixel.x + ", Y = " + (int) pixel.y;
-
- MarkerOptions marker = new MarkerOptions()
- .position(point)
- .title(title)
- .snippet(snippet);
+ addMarker(point);
+ }
+ });
- markerList.add(marker);
- mapboxMap.addMarker(marker);
+ mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
+ @Override
+ public void onMapClick(@NonNull LatLng point) {
+ addMarker(point);
}
});
@@ -79,6 +69,22 @@ public class PressForMarkerActivity extends AppCompatActivity {
});
}
+ private void addMarker(LatLng point) {
+ final PointF pixel = mapboxMap.getProjection().toScreenLocation(point);
+
+ String title = LAT_LON_FORMATTER.format(point.getLatitude()) + ", "
+ + LAT_LON_FORMATTER.format(point.getLongitude());
+ String snippet = "X = " + (int) pixel.x + ", Y = " + (int) pixel.y;
+
+ MarkerOptions marker = new MarkerOptions()
+ .position(point)
+ .title(title)
+ .snippet(snippet);
+
+ markerList.add(marker);
+ mapboxMap.addMarker(marker);
+ }
+
private void resetMap() {
if (mapboxMap == null) {
return;
@@ -139,9 +145,6 @@ public class PressForMarkerActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
case R.id.menuItemReset:
resetMap();
return true;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java
index 3d771613d4..030785565e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimationTypeActivity.java
@@ -1,10 +1,7 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -18,6 +15,12 @@ import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
+/**
+ * Test activity showcasing the Camera API and listen to camera updates by animating the camera above London.
+ * <p>
+ * Shows how to use animate, ease and move camera update factory methods.
+ * </p>
+ */
public class CameraAnimationTypeActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLng LAT_LNG_LONDON_EYE = new LatLng(51.50325, -0.11968);
@@ -32,15 +35,6 @@ public class CameraAnimationTypeActivity extends AppCompatActivity implements On
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_animation_types);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
if (mapView != null) {
mapView.onCreate(savedInstanceState);
@@ -199,15 +193,4 @@ public class CameraAnimationTypeActivity extends AppCompatActivity implements On
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
index 193b59a9db..08399f3b3e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
@@ -7,15 +7,9 @@ import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -28,6 +22,8 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import timber.log.Timber;
+
public class CameraPositionActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
@@ -38,15 +34,6 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_position);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -154,17 +141,6 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
mapView.onSaveInstanceState(outState);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
private View onInflateDialogContent(View view) {
linkTextView(view, R.id.value_lat, R.id.seekbar_lat, new LatLngChangeListener(), 180 + 38);
linkTextView(view, R.id.value_lon, R.id.seekbar_lon, new LatLngChangeListener(), 180 - 77);
@@ -214,4 +190,4 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
super.onProgressChanged(seekBar, progress - 180, fromUser);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
index 3dd6a6344d..5c33f3f168 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java
@@ -1,13 +1,7 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -23,6 +17,15 @@ import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.List;
+import timber.log.Timber;
+
+/**
+ * Test activity showcasing using the LatLngBounds camera API.
+ * <p>
+ * This activity opens the map at zoom level 0 and animates into a bounds set by Los Angeles and New York
+ * with some additional padding and an animation duration of 1500 ms.
+ * </p>
+ */
public class LatLngBoundsActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLng LOS_ANGELES = new LatLng(34.053940, -118.242622);
@@ -36,15 +39,6 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_visible_bounds);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.setStyleUrl(Style.DARK);
mapView.onCreate(savedInstanceState);
@@ -82,7 +76,7 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
// Move camera to the bounds with added padding
int padding = (int) getResources().getDimension(R.dimen.coordinatebounds_margin);
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding));
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, padding), 1500);
// Log data
Timber.e("Move to bounds: " + bounds.toString());
@@ -130,15 +124,4 @@ public class LatLngBoundsActivity extends AppCompatActivity implements OnMapRead
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
index 4bc30157f8..b999572436 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ManualZoomActivity.java
@@ -3,9 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.graphics.Point;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -18,6 +16,12 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing the zoom Camera API.
+ * <p>
+ * This includes zoomIn, zoomOut, zoomTo, zoomBy (center and custom focal point).
+ * </p>
+ */
public class ManualZoomActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
@@ -28,15 +32,6 @@ public class ManualZoomActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manual_zoom);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.setStyleUrl(Style.SATELLITE);
mapView.onCreate(savedInstanceState);
@@ -61,10 +56,6 @@ public class ManualZoomActivity extends AppCompatActivity {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
-
case R.id.action_zoom_in:
mapboxMap.animateCamera(CameraUpdateFactory.zoomIn());
return true;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java
index 71e8cc0a08..86d5b47275 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/MaxMinZoomActivity.java
@@ -1,10 +1,7 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -22,15 +19,6 @@ public class MaxMinZoomActivity extends AppCompatActivity implements OnMapReadyC
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maxmin_zoom);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -44,16 +32,6 @@ public class MaxMinZoomActivity extends AppCompatActivity implements OnMapReadyC
}
@Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- }
- return false;
- }
-
- @Override
protected void onStart() {
super.onStart();
mapView.onStart();
@@ -94,5 +72,4 @@ public class MaxMinZoomActivity extends AppCompatActivity implements OnMapReadyC
super.onLowMemory();
mapView.onLowMemory();
}
-
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java
index 2f16e862ee..2e889f6e11 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/ScrollByActivity.java
@@ -20,6 +20,9 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the scrollBy Camera API by moving x,y pixels above Grenada, Spain.
+ */
public class ScrollByActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final int MULTIPLIER_PER_PIXEL = 50;
@@ -157,4 +160,4 @@ public class ScrollByActivity extends AppCompatActivity implements OnMapReadyCal
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
index 8e4b58366f..dde22db2db 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/customlayer/CustomLayerActivity.java
@@ -3,12 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.customlayer;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -19,10 +14,15 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.style.layers.CustomLayer;
-import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.customlayer.ExampleCustomLayer;
+/**
+ * Test activity showcasing the Custom Layer API
+ * <p>
+ * Note: experimental API, do not use.
+ * </p>
+ */
public class CustomLayerActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
@@ -36,8 +36,6 @@ public class CustomLayerActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_layer);
- setupActionBar();
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -63,21 +61,17 @@ public class CustomLayerActivity extends AppCompatActivity {
private void swapCustomLayer() {
if (customLayer != null) {
- try {
- mapboxMap.removeLayer(customLayer.getId());
- customLayer = null;
- } catch (NoSuchLayerException noSuchLayerException) {
- Timber.e("No custom layer to remove");
- }
- fab.setImageResource(R.drawable.ic_layers_24dp);
+ mapboxMap.removeLayer(customLayer);
+ customLayer = null;
+ fab.setImageResource(R.drawable.ic_layers);
} else {
customLayer = new CustomLayer("custom",
ExampleCustomLayer.createContext(),
ExampleCustomLayer.InitializeFunction,
ExampleCustomLayer.RenderFunction,
ExampleCustomLayer.DeinitializeFunction);
- mapboxMap.addLayer(customLayer, "building");
- fab.setImageResource(R.drawable.ic_layers_clear_24dp);
+ mapboxMap.addLayerBelow(customLayer, "building");
+ fab.setImageResource(R.drawable.ic_layers_clear);
}
}
@@ -138,9 +132,6 @@ public class CustomLayerActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
case R.id.action_update_layer:
updateLayer();
return true;
@@ -157,15 +148,4 @@ public class CustomLayerActivity extends AppCompatActivity {
return super.onOptionsItemSelected(item);
}
}
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java
deleted file mode 100644
index 13e384a8b5..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/directions/DirectionsActivity.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.directions;
-
-import android.graphics.Color;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
-
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.annotations.PolylineOptions;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.services.Constants;
-import com.mapbox.services.api.ServicesException;
-import com.mapbox.services.commons.geojson.LineString;
-import com.mapbox.services.commons.models.Position;
-import com.mapbox.services.api.directions.v5.DirectionsCriteria;
-import com.mapbox.services.api.directions.v5.MapboxDirections;
-import com.mapbox.services.api.directions.v5.models.DirectionsResponse;
-import com.mapbox.services.api.directions.v5.models.DirectionsRoute;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class DirectionsActivity extends AppCompatActivity {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_directions);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(new OnMapReadyCallback() {
- @Override
- public void onMapReady(@NonNull MapboxMap mapboxMap) {
- DirectionsActivity.this.mapboxMap = mapboxMap;
- loadRoute();
- }
- });
- }
-
- private void loadRoute() {
- // Dupont Circle (Washington, DC)
- Position origin = Position.fromCoordinates(-77.04341, 38.90962);
-
- // The White House (Washington, DC)
- Position destination = Position.fromCoordinates(-77.0365, 38.8977);
-
- // Set map at centroid
- LatLng centroid = new LatLng(
- (origin.getLatitude() + destination.getLatitude()) / 2,
- (origin.getLongitude() + destination.getLongitude()) / 2);
-
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
- .target(centroid)
- .zoom(14)
- .build()));
-
- // Add origin and destination to the map
- mapboxMap.addMarker(new MarkerOptions()
- .position(new LatLng(origin.getLatitude(), origin.getLongitude()))
- .title("Origin")
- .snippet("Dupont Circle"));
- mapboxMap.addMarker(new MarkerOptions()
- .position(new LatLng(destination.getLatitude(), destination.getLongitude()))
- .title("Destination")
- .snippet("The White House"));
-
- // Get route from API
- getRoute(origin, destination);
- }
-
- private void getRoute(Position origin, Position destination) {
- try {
- MapboxDirections md = new MapboxDirections.Builder()
- .setAccessToken(getString(R.string.mapbox_access_token))
- .setOrigin(origin)
- .setOverview(DirectionsCriteria.OVERVIEW_FULL)
- .setDestination(destination)
- .setProfile(DirectionsCriteria.PROFILE_WALKING)
- .build();
-
- md.enqueueCall(new Callback<DirectionsResponse>() {
-
- @Override
- public void onFailure(Call<DirectionsResponse> call, Throwable throwable) {
- Timber.e("Error: " + throwable.getMessage());
- }
-
- @Override
- public void onResponse(Call<DirectionsResponse> call, Response<DirectionsResponse> response) {
- // You can get generic HTTP info about the response
- Timber.d("Response code: " + response.code());
-
- // Print some info about the route
- DirectionsRoute currentRoute = response.body().getRoutes().get(0);
- Timber.d("Distance: " + currentRoute.getDistance());
-
- // Draw the route on the map
- drawRoute(currentRoute);
- }
-
- });
- } catch (ServicesException servicesException) {
- Timber.e("Error displaying route: " + servicesException.toString());
- servicesException.printStackTrace();
- }
- }
-
- private void drawRoute(DirectionsRoute route) {
-
- PolylineOptions builder = new PolylineOptions();
- builder.color(Color.parseColor("#3887be"));
- builder.alpha(0.5f);
- builder.width(5);
- builder.width(5);
-
- LineString lineString = LineString.fromPolyline(route.getGeometry(), Constants.OSRM_PRECISION_V5);
- List<Position> coordinates = lineString.getCoordinates();
- List<LatLng> points = new ArrayList<>();
- for (int i = 0; i < coordinates.size(); i++) {
- points.add(new LatLng(
- coordinates.get(i).getLatitude(),
- coordinates.get(i).getLongitude()));
- }
-
- builder.addAll(points);
-
- // Draw Points on MapView
- mapboxMap.addPolyline(builder);
- }
-
- @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();
- mapView.onStop();
- }
-
- @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();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java
index 677e09e719..ee9f20dceb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/EspressoTestActivity.java
@@ -9,7 +9,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
/**
- * Base activity for instrumentation testing
+ * Base activity for instrumentation testing.
*/
public class EspressoTestActivity extends AppCompatActivity implements OnMapReadyCallback {
@@ -21,7 +21,7 @@ public class EspressoTestActivity extends AppCompatActivity implements OnMapRead
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_test);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java
index 00cc8dfac7..9c031ad32a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxCountActivity.java
@@ -2,10 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.RectF;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -22,7 +19,7 @@ import java.util.Map;
import timber.log.Timber;
/**
- * Demo's query rendered features
+ * Test activity showcasing using the query rendered features API to count features in a rectangle.
*/
public class QueryRenderedFeaturesBoxCountActivity extends AppCompatActivity {
@@ -33,11 +30,10 @@ public class QueryRenderedFeaturesBoxCountActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
- setupActionBar();
final View selectionBox = findViewById(R.id.selection_box);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -48,20 +44,20 @@ public class QueryRenderedFeaturesBoxCountActivity extends AppCompatActivity {
selectionBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- //Query
+ // Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i(String.format("Querying box %s", box));
List<Feature> features = mapboxMap.queryRenderedFeatures(box);
- //Show count
+ // Show count
Toast.makeText(
QueryRenderedFeaturesBoxCountActivity.this,
String.format("%s features in box", features.size()),
Toast.LENGTH_SHORT).show();
- //Debug output
+ // Debug output
debugOutput(features);
}
});
@@ -135,27 +131,4 @@ public class QueryRenderedFeaturesBoxCountActivity extends AppCompatActivity {
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java
index 8c4a499f9b..ca4fe4e4fd 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxHighlightActivity.java
@@ -3,10 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.Color;
import android.graphics.RectF;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -37,11 +34,10 @@ public class QueryRenderedFeaturesBoxHighlightActivity extends AppCompatActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
- setupActionBar();
final View selectionBox = findViewById(R.id.selection_box);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -52,28 +48,24 @@ public class QueryRenderedFeaturesBoxHighlightActivity extends AppCompatActivity
selectionBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- //Query
+ // Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i(String.format("Querying box %s for buildings", box));
List<Feature> features = mapboxMap.queryRenderedFeatures(box, "building");
- //Show count
+ // Show count
Toast.makeText(
QueryRenderedFeaturesBoxHighlightActivity.this,
String.format("%s features in box", features.size()),
Toast.LENGTH_SHORT).show();
- //remove layer / source if already added
- try {
- mapboxMap.removeSource("highlighted-shapes-source");
- mapboxMap.removeLayer("highlighted-shapes-layer");
- } catch (Exception exception) {
- //that's ok
- }
+ // remove layer / source if already added
+ mapboxMap.removeSource("highlighted-shapes-source");
+ mapboxMap.removeLayer("highlighted-shapes-layer");
- //Add layer / source
+ // Add layer / source
mapboxMap.addSource(
new GeoJsonSource("highlighted-shapes-source",
FeatureCollection.fromFeatures(features))
@@ -84,7 +76,6 @@ public class QueryRenderedFeaturesBoxHighlightActivity extends AppCompatActivity
});
}
});
-
}
public MapboxMap getMapboxMap() {
@@ -132,27 +123,4 @@ public class QueryRenderedFeaturesBoxHighlightActivity extends AppCompatActivity
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java
index 4b7bbb9614..8c2f3a8fb5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesBoxSymbolCountActivity.java
@@ -4,10 +4,7 @@ import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.annotation.RawRes;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -33,7 +30,7 @@ import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
/**
- * Demo's query rendered features on Symbols
+ * Test activity showcasing using the query rendered features API to count Symbols in a rectangle.
*/
public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivity {
@@ -46,11 +43,10 @@ public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivi
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
- setupActionBar();
final View selectionBox = findViewById(R.id.selection_box);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -59,7 +55,7 @@ public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivi
public void onMapReady(final MapboxMap mapboxMap) {
QueryRenderedFeaturesBoxSymbolCountActivity.this.mapboxMap = mapboxMap;
- //Add a symbol layer (also works with annotations)
+ // Add a symbol layer (also works with annotations)
try {
mapboxMap.addSource(new GeoJsonSource("symbols-source", readRawResource(R.raw.test_points_utrecht)));
} catch (IOException ioException) {
@@ -76,14 +72,14 @@ public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivi
selectionBox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- //Query
+ // Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i(String.format("Querying box %s", box));
List<Feature> features = mapboxMap.queryRenderedFeatures(box, "symbols-layer");
- //Show count
+ // Show count
if (toast != null) {
toast.cancel();
}
@@ -160,27 +156,4 @@ public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivi
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java
index 17dfbc18b4..8b83db3069 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/feature/QueryRenderedFeaturesPropertiesActivity.java
@@ -6,13 +6,7 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -30,8 +24,10 @@ import com.mapbox.services.commons.geojson.Feature;
import java.util.List;
import java.util.Map;
+import timber.log.Timber;
+
/**
- * Demo's query rendered features
+ * Test activity showcasing using the query rendered features API to query feature properties on Map click.
*/
public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
@@ -43,11 +39,10 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_point);
- setupActionBar();
final float density = getResources().getDisplayMetrics().density;
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -55,14 +50,14 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
public void onMapReady(final MapboxMap mapboxMap) {
QueryRenderedFeaturesPropertiesActivity.this.mapboxMap = mapboxMap;
- //Add custom window adapter
+ // Add custom window adapter
addCustomInfoWindowAdapter(mapboxMap);
- //Add a click listener
+ // Add a click listener
mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
@Override
public void onMapClick(@NonNull LatLng point) {
- //Query
+ // Query
final PointF pixel = mapboxMap.getProjection().toScreenLocation(point);
Timber.i(String.format(
"Requesting features for %sx%s (%sx%s adjusted for density)",
@@ -70,15 +65,15 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
);
List<Feature> features = mapboxMap.queryRenderedFeatures(pixel);
- //Debug output
+ // Debug output
debugOutput(features);
- //Remove any previous markers
+ // Remove any previous markers
if (marker != null) {
mapboxMap.removeMarker(marker);
}
- //Add a marker on the clicked point
+ // Add a marker on the clicked point
marker = mapboxMap.addMarker(new CustomMarkerOptions().position(point).features(features));
mapboxMap.selectMarker(marker);
}
@@ -186,28 +181,6 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
mapView.onLowMemory();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
private static class CustomMarker extends Marker {
private final List<Feature> features;
@@ -232,7 +205,7 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
}
private CustomMarkerOptions(Parcel in) {
- //Should implement this
+ // Should implement this
}
@Override
@@ -245,8 +218,8 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
return new CustomMarker(this, features);
}
- public static final Parcelable.Creator<CustomMarkerOptions> CREATOR
- = new Parcelable.Creator<CustomMarkerOptions>() {
+ public static final Parcelable.Creator<CustomMarkerOptions> CREATOR =
+ new Parcelable.Creator<CustomMarkerOptions>() {
public CustomMarkerOptions createFromParcel(Parcel in) {
return new CustomMarkerOptions(in);
}
@@ -263,7 +236,7 @@ public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
@Override
public void writeToParcel(Parcel out, int flags) {
- //Should implement this
+ // Should implement this
}
}
}
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 1c259b1304..930626078d 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
@@ -2,10 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -17,6 +14,12 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the MapFragment API using SDK Fragments.
+ * <p>
+ * Uses MapboxMapOptions to initialise the Fragment.
+ * </p>
+ */
public class MapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapboxMap mapboxMap;
@@ -26,15 +29,6 @@ public class MapFragmentActivity extends AppCompatActivity implements OnMapReady
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
MapFragment mapFragment;
if (savedInstanceState == null) {
final FragmentTransaction transaction = getFragmentManager().beginTransaction();
@@ -75,15 +69,4 @@ public class MapFragmentActivity extends AppCompatActivity implements OnMapReady
mapboxMap.animateCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000);
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java
index d5d51887dd..eec440afb0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/MultiMapActivity.java
@@ -5,6 +5,9 @@ import android.os.Bundle;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test Activity showcasing using multiple static map fragments in one layout.
+ */
public class MultiMapActivity extends AppCompatActivity {
@Override
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 7dcca89a04..ee16b251c5 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
@@ -2,10 +2,7 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -17,6 +14,12 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the MapFragment API using Support Library Fragments.
+ * <p>
+ * Uses MapboxMapOptions to initialise the Fragment.
+ * </p>
+ */
public class SupportMapFragmentActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapboxMap mapboxMap;
@@ -26,15 +29,6 @@ public class SupportMapFragmentActivity extends AppCompatActivity implements OnM
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
SupportMapFragment mapFragment;
if (savedInstanceState == null) {
final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@@ -73,15 +67,4 @@ public class SupportMapFragmentActivity extends AppCompatActivity implements OnM
mapboxMap.animateCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 10000);
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
index e6953bd3d2..8025832429 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java
@@ -5,10 +5,7 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.Style;
@@ -17,6 +14,9 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the Android SDK ViewPager API to show MapFragments.
+ */
public class ViewPagerActivity extends AppCompatActivity {
@Override
@@ -24,15 +24,6 @@ public class ViewPagerActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewpager);
- final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
if (viewPager != null) {
MapFragmentAdapter adapter = new MapFragmentAdapter(getSupportFragmentManager());
@@ -78,22 +69,10 @@ public class ViewPagerActivity extends AppCompatActivity {
return fragment;
}
-
@Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java
deleted file mode 100644
index 39d52f7876..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.geocoding;
-
-import android.graphics.PointF;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.Gravity;
-import android.view.MenuItem;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.mapbox.mapboxsdk.annotations.MarkerOptions;
-import com.mapbox.mapboxsdk.constants.Style;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.maps.Projection;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.services.api.ServicesException;
-import com.mapbox.services.commons.models.Position;
-import com.mapbox.services.api.geocoding.v5.GeocodingCriteria;
-import com.mapbox.services.api.geocoding.v5.MapboxGeocoding;
-import com.mapbox.services.api.geocoding.v5.models.CarmenFeature;
-import com.mapbox.services.api.geocoding.v5.models.GeocodingResponse;
-
-import java.util.List;
-
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-public class GeocoderActivity extends AppCompatActivity implements OnMapReadyCallback {
-
- private MapboxMap mapboxMap;
- private MapView mapView;
- private ImageView dropPinView;
- private TextView textView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_geocoder);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- textView = (TextView) findViewById(R.id.message);
- setMessage(getString(R.string.geocoder_instructions));
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.setStyleUrl(Style.MAPBOX_STREETS);
- mapView.onCreate(savedInstanceState);
-
- dropPinView = new ImageView(this);
- dropPinView.setImageResource(R.drawable.ic_droppin_24dp);
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
- dropPinView.setLayoutParams(params);
- mapView.addView(dropPinView);
- mapView.getMapAsync(this);
- }
-
- @Override
- public void onMapReady(MapboxMap map) {
- mapboxMap = map;
- final Projection projection = mapboxMap.getProjection();
- final int width = mapView.getMeasuredWidth();
- final int height = mapView.getMeasuredHeight();
-
- // Click listener
- mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
- @Override
- public void onMapClick(@NonNull LatLng point) {
- PointF centerPoint = new PointF(width / 2, (height + dropPinView.getHeight()) / 2);
- LatLng centerLatLng = new LatLng(projection.fromScreenLocation(centerPoint));
-
- setMessage("Geocoding...");
-
- mapboxMap.removeAnnotations();
- mapboxMap.addMarker(new MarkerOptions().position(centerLatLng));
-
- geocode(centerLatLng);
- }
- });
- }
-
- @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();
- mapView.onStop();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mapView.onDestroy();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mapView.onSaveInstanceState(outState);
- }
-
- /*
- * Forward geocoding
- */
-
- private void geocode(final LatLng point) {
-
- try {
- MapboxGeocoding client = new MapboxGeocoding.Builder()
- .setAccessToken(getString(R.string.mapbox_access_token))
- .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
- .setGeocodingType(GeocodingCriteria.TYPE_POI)
- .build();
-
- client.enqueueCall(new Callback<GeocodingResponse>() {
- @Override
- public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
-
- List<CarmenFeature> results = response.body().getFeatures();
- if (results.size() > 0) {
- String placeName = results.get(0).getPlaceName();
- setSuccess(placeName);
- } else {
- setMessage("No results.");
- }
-
- }
-
- @Override
- public void onFailure(Call<GeocodingResponse> call, Throwable throwable) {
- setError(throwable.getMessage());
- }
- });
- } catch (ServicesException servicesException) {
- Timber.e("Error geocoding: " + servicesException.toString());
- servicesException.printStackTrace();
- setError(servicesException.getMessage());
- }
- }
-
- /*
- * Update text view
- */
-
- private void setMessage(String message) {
- Timber.d("Message: " + message);
- textView.setText(message);
- }
-
- private void setSuccess(String placeName) {
- Timber.d("Place name: " + placeName);
- textView.setText(placeName);
- }
-
- private void setError(String message) {
- Timber.e("Error: " + message);
- textView.setText("Error: " + message);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java
index 7f3c16d7b8..18d80586c9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/PrintActivity.java
@@ -4,10 +4,7 @@ import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.print.PrintHelper;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -15,6 +12,9 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the Snaphot API to print a Map.
+ */
public class PrintActivity extends AppCompatActivity implements MapboxMap.SnapshotReadyCallback {
private MapView mapView;
@@ -25,15 +25,6 @@ public class PrintActivity extends AppCompatActivity implements MapboxMap.Snapsh
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_print);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -104,16 +95,4 @@ public class PrintActivity extends AppCompatActivity implements MapboxMap.Snapsh
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
index 3912dfa918..2be47b4e25 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java
@@ -4,10 +4,7 @@ import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
@@ -18,6 +15,9 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map.
+ */
public class SnapshotActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnClickListener {
private MapView mapView;
@@ -28,15 +28,6 @@ public class SnapshotActivity extends AppCompatActivity implements OnMapReadyCal
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_snapshot);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -112,15 +103,4 @@ public class SnapshotActivity extends AppCompatActivity implements OnMapReadyCal
super.onDestroy();
mapView.onDestroy();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java
index c70e263be5..18db2ba8a8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java
@@ -1,20 +1,14 @@
package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
+import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
@@ -25,9 +19,10 @@ import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
/**
- * Shows how to dynamically update InfoWindow when Using an MapboxMap.InfoWindowAdapter
+ * Test activity showcasing how to dynamically update InfoWindow when Using an MapboxMap.InfoWindowAdapter.
*/
public class DynamicInfoWindowAdapterActivity extends AppCompatActivity implements OnMapReadyCallback {
@@ -41,8 +36,6 @@ public class DynamicInfoWindowAdapterActivity extends AppCompatActivity implemen
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow_adapter);
- setupActionBar();
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -53,54 +46,48 @@ public class DynamicInfoWindowAdapterActivity extends AppCompatActivity implemen
mapboxMap = map;
- //Add info window adapter
+ // Add info window adapter
addCustomInfoWindowAdapter(mapboxMap);
- //Keep info windows open on click
+ // Keep info windows open on click
mapboxMap.getUiSettings().setDeselectMarkersOnTap(false);
- //Add a marker
+ // Add a marker
final MarkerView marker = addMarker(mapboxMap);
mapboxMap.selectMarker(marker);
- //On map click, change the info window contents
+ // On map click, change the info window contents
mapboxMap.setOnMapClickListener(new MapboxMap.OnMapClickListener() {
@Override
public void onMapClick(@NonNull LatLng point) {
- //Distance from click to marker
+ // Distance from click to marker
double distanceKm = marker.getPosition().distanceTo(point) / 1000;
- //Get the info window
+ // Get the info window
InfoWindow infoWindow = marker.getInfoWindow();
- //Get the view from the info window
+ // Get the view from the info window
if (infoWindow != null && infoWindow.getView() != null) {
- //Set the new text on the text view in the info window
+ // Set the new text on the text view in the info window
((TextView) infoWindow.getView()).setText(String.format("%.2fkm", distanceKm));
- //Update the info window position (as the text length changes)
+ // Update the info window position (as the text length changes)
infoWindow.update();
}
}
});
- //Focus on Paris
+ // Focus on Paris
mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(paris));
}
private MarkerView addMarker(MapboxMap mapboxMap) {
- IconFactory iconFactory = IconFactory.getInstance(this);
- Drawable iconDrawable = ContextCompat.getDrawable(this, R.drawable.ic_location_city_24dp);
- iconDrawable.setColorFilter(
- ContextCompat.getColor(DynamicInfoWindowAdapterActivity.this, R.color.mapbox_blue),
- PorterDuff.Mode.SRC_IN
- );
-
return mapboxMap.addMarker(
new MarkerViewOptions()
.position(paris)
- .icon(iconFactory.fromDrawable(iconDrawable))
- );
+ .icon(IconUtils.drawableToIcon(this, R.drawable.ic_location_city,
+ ResourcesCompat.getColor(getResources(), R.color.mapbox_blue, getTheme()))
+ ));
}
private void addCustomInfoWindowAdapter(final MapboxMap mapboxMap) {
@@ -162,26 +149,4 @@ public class DynamicInfoWindowAdapterActivity extends AppCompatActivity implemen
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
index 0c2af9b7e3..b8083dfa74 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java
@@ -2,23 +2,27 @@ package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.maps.MapView;
import java.text.DecimalFormat;
+/**
+ * Test activity showcasing using the InfoWindow API above Washington D.C.
+ * <p>
+ * Allows to test mulitple concurrently open InfoWindows.
+ * </p>
+ */
public class InfoWindowActivity extends AppCompatActivity
implements OnMapReadyCallback, MapboxMap.OnInfoWindowCloseListener, MapboxMap.OnMapLongClickListener,
MapboxMap.OnInfoWindowClickListener, MapboxMap.OnInfoWindowLongClickListener {
@@ -32,15 +36,6 @@ public class InfoWindowActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -188,9 +183,6 @@ public class InfoWindowActivity extends AppCompatActivity
toggleDeselectMarkersOnTap(!item.isChecked());
item.setChecked(!item.isChecked());
return true;
- case android.R.id.home:
- onBackPressed();
- return true;
default:
return super.onOptionsItemSelected(item);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java
index 08f64abcba..7026a797d5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowAdapterActivity.java
@@ -1,20 +1,13 @@
package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
@@ -23,31 +16,18 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.annotations.CityStateMarker;
import com.mapbox.mapboxsdk.testapp.model.annotations.CityStateMarkerOptions;
+import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
public class InfoWindowAdapterActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
- private IconFactory iconFactory;
- private Drawable iconDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow_adapter);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- iconFactory = IconFactory.getInstance(this);
- iconDrawable = ContextCompat.getDrawable(this, R.drawable.ic_location_city_24dp);
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -75,8 +55,7 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
marker.position(new LatLng(lat, lng));
marker.infoWindowBackground(color);
- iconDrawable.setColorFilter(Color.parseColor(color), PorterDuff.Mode.SRC_IN);
- Icon icon = iconFactory.fromDrawable(iconDrawable);
+ Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_location_city, Color.parseColor(color));
marker.icon(icon);
return marker;
}
@@ -144,15 +123,4 @@ public class InfoWindowAdapterActivity extends AppCompatActivity {
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
index 5c9d927e9b..6ec0ccc11f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java
@@ -3,13 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.constants.Style;
@@ -18,6 +12,11 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import timber.log.Timber;
+
+/**
+ * Test Activity showcasing the different debug modes and allows to cycle between the default map styles.
+ */
public class DebugModeActivity extends AppCompatActivity {
private MapView mapView;
@@ -39,15 +38,6 @@ public class DebugModeActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_debug_mode);
- final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.setTag(true);
mapView.setStyleUrl(STYLES[currentStyleIndex]);
@@ -127,16 +117,4 @@ public class DebugModeActivity extends AppCompatActivity {
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
-
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
index 6c43e28237..7ec9cb9242 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DoubleMapActivity.java
@@ -6,11 +6,8 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
@@ -38,15 +35,6 @@ public class DoubleMapActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
if (savedInstanceState == null) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, new DoubleMapFragment(), TAG_FRAGMENT);
@@ -189,15 +177,4 @@ public class DoubleMapActivity extends AppCompatActivity {
mapViewMini.onSaveInstanceState(outState);
}
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
index ed3f315e06..495360a168 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapInDialogActivity.java
@@ -4,11 +4,8 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -16,6 +13,12 @@ import android.widget.Button;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing showing a Map inside of a DialogFragment.
+ * <p>
+ * Uses the deprecated TextureView API to workaround the issue of seeing a grey background before the gl surface.
+ * </p>
+ */
public class MapInDialogActivity extends AppCompatActivity {
@Override
@@ -23,15 +26,6 @@ public class MapInDialogActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_in_dialog);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
Button button = (Button) findViewById(R.id.button_open_dialog);
button.setOnClickListener(new View.OnClickListener() {
@Override
@@ -43,17 +37,6 @@ public class MapInDialogActivity extends AppCompatActivity {
});
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
public static class MapDialogFragment extends DialogFragment {
private MapView mapView;
@@ -124,4 +107,4 @@ public class MapInDialogActivity extends AppCompatActivity {
mapView.onSaveInstanceState(outState);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java
index 90b91057ed..0cf0191cea 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/MapPaddingActivity.java
@@ -2,23 +2,27 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing using the map padding API.
+ * <p>
+ * This activity tests for correct padding around a marker (Bangalore) and correct padding around MyLocationView.
+ * </p>
+ */
public class MapPaddingActivity extends AppCompatActivity {
private MapView mapView;
@@ -29,15 +33,6 @@ public class MapPaddingActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_padding);
- final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.setTag(true);
mapView.onCreate(savedInstanceState);
@@ -50,7 +45,8 @@ public class MapPaddingActivity extends AppCompatActivity {
int paddingLeft = (int) getResources().getDimension(R.dimen.map_padding_left);
int paddingBottom = (int) getResources().getDimension(R.dimen.map_padding_bottom);
int paddingRight = (int) getResources().getDimension(R.dimen.map_padding_right);
- mapboxMap.setPadding(paddingLeft, toolbar.getHeight(), paddingRight, paddingBottom);
+ int paddingTop = (int) getResources().getDimension(R.dimen.map_padding_top);
+ mapboxMap.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
moveToBangalore();
}
@@ -138,10 +134,6 @@ public class MapPaddingActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
-
case R.id.action_user_tracking:
if (mapboxMap != null) {
toggleGps(true);
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java
index 7f59dd3bdb..888482b219 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/NavigationDrawerActivity.java
@@ -148,8 +148,8 @@ public class NavigationDrawerActivity extends AppCompatActivity {
android.R.layout.simple_list_item_activated_1,
android.R.id.text1,
new String[] {
- getString(R.string.title_section1),
- getString(R.string.title_section2)
+ "Different style",
+ "Show snackbar"
}));
drawerListView.setItemChecked(currentSelectedPosition, true);
return drawerListView;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java
index 7e04b95e20..8f8a5af3cc 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java
@@ -1,14 +1,14 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.testapp.R;
+/**
+ * Test activity showcasing a simple MapView without any MapboxMap interaction.
+ */
public class SimpleMapActivity extends AppCompatActivity {
private MapView mapView;
@@ -18,15 +18,6 @@ public class SimpleMapActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_simple);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
}
@@ -72,15 +63,4 @@ public class SimpleMapActivity extends AppCompatActivity {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/CarDrivingActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/CarDrivingActivity.java
deleted file mode 100644
index 4bb6bc5f39..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/CarDrivingActivity.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.navigation;
-
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.location.Location;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
-
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.constants.MyBearingTracking;
-import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.maps.TrackingSettings;
-import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
-import com.mapbox.mapboxsdk.testapp.R;
-
-public class CarDrivingActivity extends AppCompatActivity implements MapboxMap.OnMyLocationChangeListener {
-
- private static final int PERMISSIONS_LOCATION = 0;
-
- private MapView mapView;
- private MapboxMap mapboxMap;
- private Location location;
-
- @Override
- protected void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_car_driving);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(new OnMapReadyCallback() {
- @Override
- public void onMapReady(@NonNull MapboxMap mapboxMap) {
- CarDrivingActivity.this.mapboxMap = mapboxMap;
-
- // view settings
- MyLocationViewSettings settings = mapboxMap.getMyLocationViewSettings();
- settings.setPadding(0, getWindow().getDecorView().getMeasuredHeight() / 3, 0, 0);
-
- // get car
- Drawable car = ResourcesCompat.getDrawable(getResources(), R.drawable.ic_taxi_top_small, getTheme());
- settings.setForegroundTintColor(Color.TRANSPARENT);
- settings.setForegroundDrawable(car, car);
-
- // remove accuracy circle
- settings.setAccuracyAlpha(0);
-
- // disable dismissal when a gesture occurs
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setDismissLocationTrackingOnGesture(false);
- trackingSettings.setDismissBearingTrackingOnGesture(false);
-
- mapboxMap.setOnMyLocationChangeListener(CarDrivingActivity.this);
-
- if (savedInstanceState == null) {
- toggleGps(true);
- }
- }
- });
- }
-
- @UiThread
- public void toggleGps(boolean enableGps) {
- if (enableGps) {
- if ((ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
- || (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- ActivityCompat.requestPermissions(this, new String[] {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
- } else {
- enableLocation(true);
- }
- } else {
- enableLocation(false);
- }
- }
-
- private void enableLocation(boolean enabled) {
- if (enabled) {
- mapboxMap.setMyLocationEnabled(true);
- Location location = mapboxMap.getMyLocation();
- if (location != null) {
- setInitialPosition(new LatLng(location));
- }
- } else {
- mapboxMap.setMyLocationEnabled(false);
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == PERMISSIONS_LOCATION) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- enableLocation(true);
- }
- }
- }
-
- private void setInitialPosition(LatLng latLng) {
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder().target(latLng).zoom(15).tilt(20f).build()));
- mapboxMap.setMyLocationEnabled(true);
-
- TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
- trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
- trackingSettings.setMyBearingTrackingMode(MyBearingTracking.GPS);
- }
-
- @Override
- public void onMyLocationChange(@Nullable Location location) {
- if (location != null) {
- if (this.location == null) {
- // initial location to reposition map
- setInitialPosition(new LatLng(location));
- }
- this.location = location;
- }
- }
-
- @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();
- mapView.onStop();
- }
-
- @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();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java
deleted file mode 100644
index 8fb53645a1..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java
+++ /dev/null
@@ -1,477 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.navigation;
-
-import android.Manifest;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.graphics.PointF;
-import android.location.Location;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.app.ActivityCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.Toast;
-
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerView;
-import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerViewOptions;
-import com.mapbox.services.api.ServicesException;
-import com.mapbox.services.commons.models.Position;
-import com.mapbox.services.api.geocoding.v5.GeocodingCriteria;
-import com.mapbox.services.api.geocoding.v5.MapboxGeocoding;
-import com.mapbox.services.api.geocoding.v5.models.CarmenFeature;
-import com.mapbox.services.api.geocoding.v5.models.GeocodingResponse;
-
-import java.util.List;
-
-import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
-
-/**
- * Sample Activity to show a typical location picker use case
- */
-public class LocationPickerActivity extends AppCompatActivity {
- private static final int REQUEST_PERMISSIONS = 101;
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- private ImageView dropPinView;
- private Marker addressPin;
- private ImageButton clearDisplayViewButton;
- private MarkerView userMarker;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_location_picker);
-
- setupActionBar();
-
- //Initialize map as normal
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
-
- //Create ui elements
- createDropPin();
- createSelectLocationButton();
- createClearSelectionButton();
-
- mapView.getMapAsync(new OnMapReadyCallback() {
- @Override
- public void onMapReady(MapboxMap map) {
- //Store for later
- mapboxMap = map;
-
- //Add user marker
- mapboxMap.getMarkerViewManager().addMarkerViewAdapter(
- new PulseMarkerViewAdapter(LocationPickerActivity.this));
- userMarker = createCustomUserMarker(new LatLng(0, 0));
-
- //Fix the focal point to the center of the map
- PointF focalPoint = new PointF(
- (mapView.getX() + mapView.getWidth() / 2), (mapView.getY() + mapView.getHeight() / 2));
- mapboxMap.getUiSettings().setFocalPoint(focalPoint);
-
- //Track camera updates to animate the user location views
- trackUserLocationView(userMarker);
- }
- });
- }
-
- private void zoomInOn(Location location) {
- //Move the camera to the user
- if (location != null) {
- mapboxMap.setCameraPosition(new CameraPosition.Builder()
- .target(new LatLng(location))
- .zoom(16)
- .bearing(0)
- .tilt(0)
- .build());
- }
- }
-
-
- /**
- * Tracks the camera to animate the marker when overlapping with the picker.
- * Makes sure the marker actually points to the user's position by tracking it.
- */
- private void trackUserLocationView(final MarkerView markerView) {
- final float circleDiameterSize = getResources().getDimension(R.dimen.circle_size);
-
- //Track camera changes to check for overlap
- mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() {
-
- private Animation pulseAnimation;
-
- @Override
- public void onCameraChange(CameraPosition position) {
- if (markerView == null) {
- return;
- }
-
- //Make drop pin visible, if it wasn't already
- showDropPin();
-
- //Get the distance from the tip of the location picker to the MarkerView
- double distance = getLocationPickerLocation().distanceTo(markerView.getPosition());
-
- //If closeby, animate, otherwise, stop animation
- View view = mapboxMap.getMarkerViewManager().getView(markerView);
- if (view != null) {
- View backgroundView = view.findViewById(R.id.background_imageview);
- if (pulseAnimation == null && distance < 0.5f * circleDiameterSize) {
- pulseAnimation = AnimationUtils.loadAnimation(LocationPickerActivity.this, R.anim.pulse);
- pulseAnimation.setRepeatCount(Animation.INFINITE);
- pulseAnimation.setRepeatMode(Animation.RESTART);
- backgroundView.startAnimation(pulseAnimation);
- } else if (pulseAnimation != null && distance >= 0.5f * circleDiameterSize) {
- backgroundView.clearAnimation();
- pulseAnimation = null;
- }
- }
- }
- });
-
- //Track location updates to move the user marker
- LocationServices.getLocationServices(getApplicationContext()).addLocationListener(new LocationListener() {
- @Override
- public void onLocationChanged(Location location) {
- if (location != null && markerView != null) {
- markerView.setPosition(new LatLng(location));
- }
- }
- });
- }
-
- private MarkerView createCustomUserMarker(LatLng markerPosition) {
- return mapboxMap.addMarker(new PulseMarkerViewOptions()
- .icon(IconFactory.getInstance(getApplicationContext()).fromResource(R.drawable.ic_my_location_24dp))
- .position(markerPosition)
- );
- }
-
- private void createClearSelectionButton() {
- clearDisplayViewButton = (ImageButton) findViewById(R.id.clearDisplayViewButton);
- clearDisplayViewButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- removeAddressPin();
- hide(clearDisplayViewButton);
- showDropPin();
- }
- });
- }
-
- private void createSelectLocationButton() {
- Button selectLocationButton = (Button) findViewById(R.id.selectLocationButton);
- //noinspection ConstantConditions
- selectLocationButton.setOnClickListener(
- new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Timber.i("Location Selected!");
- if (mapboxMap != null) {
- //Control button's state
- clearDisplayViewButton.setVisibility(View.VISIBLE);
- dropPinView.setVisibility(View.INVISIBLE);
-
- //Get position for the drop pin
- LatLng position = getLocationPickerLocation();
-
- //Show the address pin (result)
- showAddressPin(position);
-
- //Get the address for that location and update the marker
- geocode(position, new GeocodeCallbacks() {
- @Override
- public void onResult(String result) {
- updateAddressPin(result);
- }
-
- @Override
- public void onFailure(Throwable failure) {
- showFeedbackMessage("Could not retrieve address: " + failure.getMessage());
- }
- });
- }
- }
- }
- );
- }
-
- private void createDropPin() {
- float density = getResources().getDisplayMetrics().density;
-
- dropPinView = new ImageView(this);
- dropPinView.setImageResource(R.drawable.ic_droppin_24dp);
- FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
- params.bottomMargin = (int) (12 * density);
- dropPinView.setLayoutParams(params);
-
- mapView.addView(dropPinView);
- }
-
- private void showDropPin() {
- if (dropPinView != null && dropPinView.getVisibility() != View.VISIBLE) {
- dropPinView.setVisibility(View.VISIBLE);
- }
- }
-
- private void hide(View view) {
- if (view != null) {
- view.setVisibility(View.INVISIBLE);
- }
- }
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
- /**
- * Get address for the given location
- */
- private void geocode(LatLng point, final GeocodeCallbacks callbacks) {
- try {
- //Create Geocoding client
- MapboxGeocoding client = new MapboxGeocoding.Builder()
- .setAccessToken(getString(R.string.mapbox_access_token))
- .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude()))
- .setGeocodingType(GeocodingCriteria.TYPE_ADDRESS)
- .build();
-
- //Place the request
- client.enqueueCall(new Callback<GeocodingResponse>() {
- @Override
- public void onResponse(Call<GeocodingResponse> call, Response<GeocodingResponse> response) {
-
- List<CarmenFeature> results = response.body().getFeatures();
- String address = null;
- if (results.size() > 0) {
- CarmenFeature feature = results.get(0);
- address = feature.getAddress() + " " + feature.getText();
- Timber.i("address " + address);
- } else {
- showFeedbackMessage("No results for search.");
- }
-
- callbacks.onResult(address);
- }
-
- @Override
- public void onFailure(Call<GeocodingResponse> call, Throwable throwable) {
- Timber.e("Geocoding Failure: " + throwable.getMessage());
- callbacks.onFailure(throwable);
- }
- });
- } catch (ServicesException servicesException) {
- Timber.e("Error geocoding: " + servicesException.toString());
- callbacks.onFailure(servicesException);
- }
- }
-
- private LatLng getLocationPickerLocation() {
- return mapboxMap.getProjection().fromScreenLocation(
- new PointF(dropPinView.getLeft() + (dropPinView.getWidth() / 2), dropPinView.getBottom())
- );
- }
-
- private Marker showAddressPin(LatLng position) {
- if (addressPin != null) {
- //Remove previous pin
- removeAddressPin();
- }
-
- //Create new one
- addressPin = mapboxMap.addMarker(new MarkerViewOptions().title("Loading address...").position(position));
- mapboxMap.selectMarker(addressPin);
- return addressPin;
- }
-
- private void removeAddressPin() {
- if (mapboxMap != null && addressPin != null) {
- mapboxMap.removeMarker(addressPin);
- }
- }
-
- private void updateAddressPin(@Nullable String address) {
- if (addressPin != null) {
- addressPin.setTitle(address == null ? "No address found" : address);
- }
- }
-
- private void showFeedbackMessage(String message) {
- Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
- }
-
- private boolean arePermissionsGranted() {
- if (Build.VERSION.SDK_INT >= 23
- && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
- && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- Timber.i("Requesting permissions");
- ActivityCompat.requestPermissions(this, new String[] {
- Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS);
- return false;
- }
- Timber.i("Permissions already granted");
- return true;
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mapView.onStart();
-
- //Check permissions
- if (arePermissionsGranted()) {
- mapView.getMapAsync(new OnMapReadyCallback() {
-
- @Override
- public void onMapReady(final MapboxMap mapboxMap) {
- //Get the user's location
- final LocationServices locationServices = LocationServices.getLocationServices(getApplicationContext());
-
- Location location = locationServices.getLastLocation();
- if (location != null) {
- zoomInOn(location);
- userMarker.setPosition(new LatLng(location));
- } else {
- final ProgressDialog loadingDialog = ProgressDialog.show(
- LocationPickerActivity.this, "Loading", "Getting user location", false);
- locationServices.addLocationListener(new LocationListener() {
- @Override
- public void onLocationChanged(@Nullable Location location) {
- //Move the camera to the user
- if (location != null) {
- zoomInOn(location);
- userMarker.setPosition(new LatLng(location));
- locationServices.removeLocationListener(this);
- loadingDialog.hide();
- }
- }
- });
- }
-
- locationServices.toggleGPS(true);
- }
- });
- }
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mapView.onPause();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- mapView.onStop();
- }
-
- @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();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- /**
- * Custom MarkerViewAdapter for the pulsing marker
- */
- private static class PulseMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<PulseMarkerView> {
-
- private LayoutInflater inflater;
-
- public PulseMarkerViewAdapter(@NonNull Context context) {
- super(context);
- this.inflater = LayoutInflater.from(context);
- }
-
- @Nullable
- @Override
- public View getView(@NonNull PulseMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) {
- ViewHolder viewHolder;
- if (convertView == null) {
- viewHolder = new ViewHolder();
- convertView = inflater.inflate(R.layout.view_pulse_marker, parent, false);
- viewHolder.foregroundImageView = (ImageView) convertView.findViewById(R.id.foreground_imageView);
- viewHolder.backgroundImageView = (ImageView) convertView.findViewById(R.id.background_imageview);
- convertView.setTag(viewHolder);
- }
- return convertView;
- }
-
- private static class ViewHolder {
- ImageView foregroundImageView;
- ImageView backgroundImageView;
- }
- }
-
- private interface GeocodeCallbacks {
- void onResult(String result);
-
- void onFailure(Throwable failure);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java
new file mode 100644
index 0000000000..220f46f4e8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/DeleteRegionActivity.java
@@ -0,0 +1,168 @@
+package com.mapbox.mapboxsdk.testapp.activity.offline;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.mapbox.mapboxsdk.offline.OfflineManager;
+import com.mapbox.mapboxsdk.offline.OfflineRegion;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test activity showing integration of deleting an OfflineRegion.
+ */
+public class DeleteRegionActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
+
+ private OfflineRegionAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_offline_region_delete);
+
+ ListView listView = (ListView) findViewById(R.id.listView);
+ listView.setAdapter(adapter = new OfflineRegionAdapter(this));
+ listView.setEmptyView(findViewById(android.R.id.empty));
+ listView.setOnItemClickListener(this);
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final OfflineRegion region = adapter.getItem(position);
+ String metadata = OfflineUtils.convertRegionName(region.getMetadata());
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Delete region");
+
+ final TextView input = new TextView(this);
+ input.setText(metadata);
+ builder.setView(input);
+
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ delete(region);
+ }
+ });
+ builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.cancel();
+ }
+ });
+
+ builder.show();
+ }
+
+ private void delete(OfflineRegion region) {
+ region.delete(new OfflineRegion.OfflineRegionDeleteCallback() {
+ @Override
+ public void onDelete() {
+ Toast.makeText(
+ DeleteRegionActivity.this,
+ "Region deleted",
+ Toast.LENGTH_SHORT
+ ).show();
+ loadOfflineRegions();
+ }
+
+ @Override
+ public void onError(String error) {
+ Toast.makeText(
+ DeleteRegionActivity.this,
+ "Region deletion failed with " + error,
+ Toast.LENGTH_LONG
+ ).show();
+ }
+ });
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ loadOfflineRegions();
+ }
+
+ private void loadOfflineRegions() {
+ OfflineManager.getInstance(this).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
+ @Override
+ public void onList(OfflineRegion[] offlineRegions) {
+ if (offlineRegions != null && offlineRegions.length > 0) {
+ adapter.setOfflineRegions(Arrays.asList(offlineRegions));
+ }
+ }
+
+ @Override
+ public void onError(String error) {
+ Toast.makeText(DeleteRegionActivity.this, "Error loading regions " + error, Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+
+ private static class OfflineRegionAdapter extends BaseAdapter {
+
+ private Context context;
+ private List<OfflineRegion> offlineRegions;
+
+ OfflineRegionAdapter(Context ctx) {
+ context = ctx;
+ offlineRegions = new ArrayList<>();
+ }
+
+ void setOfflineRegions(List<OfflineRegion> offlineRegions) {
+ this.offlineRegions = offlineRegions;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return offlineRegions.size();
+ }
+
+ @Override
+ public OfflineRegion getItem(int position) {
+ return offlineRegions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+
+ if (convertView == null) {
+ holder = new ViewHolder();
+ convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
+ holder.text = (TextView) convertView.findViewById(android.R.id.text1);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ holder.text.setText(OfflineUtils.convertRegionName(getItem(position).getMetadata()));
+ return convertView;
+ }
+
+ static class ViewHolder {
+ TextView text;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
index e2eda0e6b1..be5d809457 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java
@@ -2,11 +2,8 @@ package com.mapbox.mapboxsdk.testapp.activity.offline;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
@@ -36,6 +33,12 @@ import java.util.ArrayList;
import timber.log.Timber;
+/**
+ * Test activity showcasing the Offline API.
+ * <p>
+ * Shows a map of Manhattan and allows the user to download and name a region.
+ * </p>
+ */
public class OfflineActivity extends AppCompatActivity
implements OfflineDownloadRegionDialog.DownloadRegionDialogListener {
@@ -68,18 +71,9 @@ public class OfflineActivity extends AppCompatActivity
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_offline);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
// You can use Mapbox.setConnected(Boolean) to manually set the connectivity
// state of your app. This will override any checks performed via the ConnectivityManager.
- //Mapbox.getInstance().setConnected(false);
+ // Mapbox.getInstance().setConnected(false);
Boolean connected = Mapbox.isConnected();
Timber.d(String.format(MapboxConstants.MAPBOX_LOCALE,
"Mapbox is connected: %b", connected));
@@ -171,17 +165,6 @@ public class OfflineActivity extends AppCompatActivity
mapView.onLowMemory();
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
/*
* Buttons logic
*/
@@ -283,6 +266,7 @@ public class OfflineActivity extends AppCompatActivity
if (status.isComplete()) {
// Download complete
endProgress("Region downloaded successfully.");
+ offlineRegion.setObserver(null);
return;
} else if (status.isRequiredResourceCountPrecise()) {
// Switch to determinate state
@@ -300,6 +284,7 @@ public class OfflineActivity extends AppCompatActivity
public void onError(OfflineRegionError error) {
Timber.e("onError reason: " + error.getReason());
Timber.e("onError message: " + error.getMessage());
+ offlineRegion.setObserver(null);
}
@Override
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 a83cabba12..285e896766 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
@@ -3,13 +3,10 @@ package com.mapbox.mapboxsdk.testapp.activity.offline;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
@@ -40,15 +37,6 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_metadata_update);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
ListView listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter = new OfflineRegionMetadataAdapter(this));
listView.setEmptyView(findViewById(android.R.id.empty));
@@ -125,17 +113,6 @@ public class UpdateMetadataActivity extends AppCompatActivity implements Adapter
});
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
private static class OfflineRegionMetadataAdapter extends BaseAdapter {
private Context context;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
index 0b102057b7..7628d6391e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CircleLayerActivity.java
@@ -5,13 +5,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraPosition;
@@ -28,10 +22,18 @@ import com.mapbox.mapboxsdk.testapp.R;
import java.net.MalformedURLException;
import java.net.URL;
+import timber.log.Timber;
+
import static com.mapbox.mapboxsdk.style.layers.Filter.in;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
+/**
+ * Test activity showcasing adding a Circle Layer to the Map
+ * <p>
+ * Uses bus stop data from Singapore as a source and allows to filter into 1 specific route with a line layer.
+ * </p>
+ */
public class CircleLayerActivity extends AppCompatActivity {
private static final String[] STOPS_FOR_ROUTE = new String[] {"99009", "99131", "99049", "99039", "99029", "99019",
@@ -50,15 +52,6 @@ public class CircleLayerActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle_layer);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -87,7 +80,7 @@ public class CircleLayerActivity extends AppCompatActivity {
public void onClick(View view) {
// filter out stops for our route
- layer.setFilter(in("number", STOPS_FOR_ROUTE));
+ layer.setFilter(in("number", (Object[]) STOPS_FOR_ROUTE));
// add route as a line
try {
@@ -98,7 +91,7 @@ public class CircleLayerActivity extends AppCompatActivity {
Timber.e("That's not an url... ", malformedUrlException);
}
LineLayer lineLayer = new LineLayer("route_layer", "bus_route");
- mapboxMap.addLayer(lineLayer, "stops_layer");
+ mapboxMap.addLayerBelow(lineLayer, "stops_layer");
// move camera to start route
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
@@ -156,15 +149,4 @@ public class CircleLayerActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java
index d68872a5ba..3763b45e7a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/CustomSpriteActivity.java
@@ -5,13 +5,7 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -28,10 +22,12 @@ import com.mapbox.services.commons.geojson.FeatureCollection;
import com.mapbox.services.commons.geojson.Point;
import com.mapbox.services.commons.models.Position;
+import timber.log.Timber;
+
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
/**
- * Example to add a sprite image and use it in a Symbol Layer
+ * Test activity showcasing adding a sprite image and use it in a Symbol Layer
*/
public class CustomSpriteActivity extends AppCompatActivity {
private static final String CUSTOM_ICON = "custom-icon";
@@ -47,15 +43,6 @@ public class CustomSpriteActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_sprite);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -74,7 +61,7 @@ public class CustomSpriteActivity extends AppCompatActivity {
// Add an icon to reference later
mapboxMap.addImage(CUSTOM_ICON, BitmapFactory.decodeResource(getResources(), R.drawable.ic_car_top));
- //Add a source with a geojson point
+ // Add a source with a geojson point
point = Point.fromCoordinates(Position.fromCoordinates(13.400972d, 52.519003d));
source = new GeoJsonSource(
"point",
@@ -82,26 +69,26 @@ public class CustomSpriteActivity extends AppCompatActivity {
);
mapboxMap.addSource(source);
- //Add a symbol layer that references that point source
+ // Add a symbol layer that references that point source
layer = new SymbolLayer("layer", "point");
layer.setProperties(
- //Set the id of the sprite to use
+ // Set the id of the sprite to use
iconImage(CUSTOM_ICON)
);
// lets add a circle below labels!
- mapboxMap.addLayer(layer, "waterway-label");
+ mapboxMap.addLayerBelow(layer, "waterway-label");
- fab.setImageResource(R.drawable.ic_directions_car_black_24dp);
+ fab.setImageResource(R.drawable.ic_directions_car_black);
} else {
- //Update point
+ // Update point
point = Point.fromCoordinates(
Position.fromCoordinates(point.getCoordinates().getLongitude() + 0.001,
point.getCoordinates().getLatitude() + 0.001)
);
source.setGeoJson(FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(point)}));
- //Move the camera as well
+ // Move the camera as well
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(
point.getCoordinates().getLatitude(), point.getCoordinates().getLongitude())));
}
@@ -152,15 +139,4 @@ public class CustomSpriteActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java
new file mode 100644
index 0000000000..3a5b30f71f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/DataDrivenStyleActivity.java
@@ -0,0 +1,395 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.RawRes;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.functions.stops.Stops;
+import com.mapbox.mapboxsdk.style.layers.FillLayer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.style.sources.Source;
+import com.mapbox.mapboxsdk.testapp.R;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import timber.log.Timber;
+
+import static com.mapbox.mapboxsdk.style.functions.Function.composite;
+import static com.mapbox.mapboxsdk.style.functions.Function.property;
+import static com.mapbox.mapboxsdk.style.functions.Function.zoom;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.categorical;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.exponential;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.interval;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
+
+/**
+ * Test activity showcasing the data driven runtime style API.
+ */
+public class DataDrivenStyleActivity extends AppCompatActivity {
+
+ public static final String AMSTERDAM_PARKS_LAYER = "amsterdam-parks-layer";
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_data_driven_style);
+
+ // Initialize map as normal
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+
+
+ mapView.getMapAsync(new OnMapReadyCallback() {
+ @Override
+ public void onMapReady(MapboxMap map) {
+ // Store for later
+ mapboxMap = map;
+
+ // Add a parks layer
+ addParksLayer();
+
+ // Center and Zoom (Amsterdam, zoomed to streets)
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_data_driven_style, menu);
+ return true;
+ }
+
+ @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();
+ mapView.onStop();
+ }
+
+ @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();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.action_add_exponential_zoom_function:
+ addExponentialZoomFunction();
+ return true;
+ case R.id.action_add_interval_zoom_function:
+ addIntervalZoomFunction();
+ return true;
+ case R.id.action_add_categorical_source_function:
+ addCategoricalSourceFunction();
+ return true;
+ case R.id.action_add_exponential_source_function:
+ addExponentialSourceFunction();
+ return true;
+ case R.id.action_add_identity_source_function:
+ addIdentitySourceFunction();
+ return true;
+ case R.id.action_add_interval_source_function:
+ addIntervalSourceFunction();
+ return true;
+ case R.id.action_add_composite_categorical_function:
+ addCompositeCategoricalFunction();
+ return true;
+ case R.id.action_add_composite_exponential_function:
+ addCompositeExponentialFunction();
+ return true;
+ case R.id.action_add_composite_interval_function:
+ addCompositeIntervalFunction();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+
+ private void addExponentialZoomFunction() {
+ Timber.i("Add exponential zoom function");
+ FillLayer layer = mapboxMap.getLayerAs("water");
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ zoom(
+ exponential(
+ stop(1, fillColor(Color.RED)),
+ stop(5, fillColor(Color.BLUE)),
+ stop(10, fillColor(Color.GREEN))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addIntervalZoomFunction() {
+ Timber.i("Add interval zoom function");
+ FillLayer layer = mapboxMap.getLayerAs("water");
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ zoom(
+ interval(
+ stop(1, fillColor(Color.RED)),
+ stop(5, fillColor(Color.BLUE)),
+ stop(10, fillColor(Color.GREEN))
+ )
+ )
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addExponentialSourceFunction() {
+ Timber.i("Add exponential source function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ property(
+ "stroke-width",
+ exponential(
+ stop(1f, fillColor(Color.RED)),
+ stop(5f, fillColor(Color.BLUE)),
+ stop(10f, fillColor(Color.GREEN))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addCategoricalSourceFunction() {
+ Timber.i("Add categorical source function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ property(
+ "name",
+ categorical(
+ stop("Westerpark", fillColor(Color.RED)),
+ stop("Jordaan", fillColor(Color.BLUE)),
+ stop("Prinseneiland", fillColor(Color.GREEN))
+ ))
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addIdentitySourceFunction() {
+ Timber.i("Add identity source function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillOpacity(
+ property(
+ "fill-opacity",
+ Stops.<Float>identity())
+ )
+ );
+
+ Timber.i("Fill opacity: %s", layer.getFillOpacity());
+ }
+
+ private void addIntervalSourceFunction() {
+ Timber.i("Add interval source function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ property(
+ "stroke-width",
+ interval(
+ stop(1f, fillColor(Color.RED)),
+ stop(5f, fillColor(Color.BLUE)),
+ stop(10f, fillColor(Color.GREEN))
+ ))
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addCompositeExponentialFunction() {
+ Timber.i("Add composite exponential function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ composite(
+ "stroke-width",
+ exponential(
+ stop(1, 1, fillColor(Color.RED)),
+ stop(10, 2, fillColor(Color.BLUE)),
+ stop(22, 3, fillColor(Color.GREEN)),
+ stop(1, 1, fillColor(Color.CYAN)),
+ stop(10, 2, fillColor(Color.GRAY)),
+ stop(22, 3, fillColor(Color.YELLOW))
+ ).withBase(1f)
+ )
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addCompositeIntervalFunction() {
+ Timber.i("Add composite exponential function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ composite(
+ "stroke-width",
+ interval(
+ stop(1, 1, fillColor(Color.RED)),
+ stop(10, 2, fillColor(Color.BLUE)),
+ stop(22, 3, fillColor(Color.GREEN)),
+ stop(1, 1, fillColor(Color.CYAN)),
+ stop(10, 2, fillColor(Color.GRAY)),
+ stop(22, 3, fillColor(Color.YELLOW))
+ ))
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addCompositeCategoricalFunction() {
+ Timber.i("Add composite categorical function");
+ FillLayer layer = mapboxMap.getLayerAs(AMSTERDAM_PARKS_LAYER);
+ assert layer != null;
+ layer.setProperties(
+ fillColor(
+ composite(
+ "name",
+ categorical(
+ stop(7f, "Westerpark", fillColor(Color.RED)),
+ stop(8f, "Westerpark", fillColor(Color.BLUE)),
+ stop(9f, "Westerpark", fillColor(Color.RED)),
+ stop(10f, "Westerpark", fillColor(Color.BLUE)),
+ stop(11f, "Westerpark", fillColor(Color.RED)),
+ stop(12f, "Westerpark", fillColor(Color.BLUE)),
+ stop(13f, "Westerpark", fillColor(Color.RED)),
+ stop(14f, "Westerpark", fillColor(Color.BLUE)),
+ stop(15f, "Westerpark", fillColor(Color.RED)),
+ stop(16f, "Westerpark", fillColor(Color.BLUE)),
+ stop(17f, "Westerpark", fillColor(Color.RED)),
+ stop(18f, "Westerpark", fillColor(Color.BLUE)),
+ stop(19f, "Westerpark", fillColor(Color.RED)),
+ stop(20f, "Westerpark", fillColor(Color.BLUE)),
+ stop(21f, "Westerpark", fillColor(Color.RED)),
+ stop(22f, "Westerpark", fillColor(Color.BLUE)),
+ stop(14f, "Jordaan", fillColor(Color.GREEN)),
+ stop(18f, "Jordaan", fillColor(Color.CYAN)),
+ stop(14f, "Prinseneiland", fillColor(Color.WHITE)),
+ stop(18f, "Prinseneiland", fillColor(Color.BLACK))
+ ))
+ )
+ );
+
+ Timber.i("Fill color: %s", layer.getFillColor());
+ }
+
+ private void addParksLayer() {
+ // Add a source
+ Source source;
+ try {
+ source = new GeoJsonSource("amsterdam-parks-source", readRawResource(R.raw.amsterdam));
+ mapboxMap.addSource(source);
+ } catch (IOException ioException) {
+ Toast.makeText(
+ DataDrivenStyleActivity.this,
+ "Couldn't add source: " + ioException.getMessage(),
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+
+ // Add a fill layer
+ mapboxMap.addLayer(new FillLayer(AMSTERDAM_PARKS_LAYER, source.getId())
+ .withProperties(
+ fillColor(Color.BLACK),
+ fillOutlineColor(Color.BLUE),
+ fillAntialias(true)
+ )
+ );
+ }
+
+ private String readRawResource(@RawRes int rawResource) throws IOException {
+ InputStream is = getResources().openRawResource(rawResource);
+ Writer writer = new StringWriter();
+ char[] buffer = new char[1024];
+ try {
+ Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+ int numRead;
+ while ((numRead = reader.read(buffer)) != -1) {
+ writer.write(buffer, 0, numRead);
+ }
+ } finally {
+ is.close();
+ }
+
+ return writer.toString();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
index 33fc7f60a6..80dfe777cb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
@@ -3,12 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
import android.view.MenuItem;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
@@ -25,6 +20,8 @@ import com.mapbox.mapboxsdk.testapp.R;
import java.net.MalformedURLException;
import java.net.URL;
+import timber.log.Timber;
+
import static com.mapbox.mapboxsdk.style.layers.Filter.all;
import static com.mapbox.mapboxsdk.style.layers.Filter.gte;
import static com.mapbox.mapboxsdk.style.layers.Filter.lt;
@@ -36,7 +33,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
- * Sample Activity to show off geojson source clustering and filter usage
+ * Test activity showcasing using a geojson source and visualise that source as a cluster by using filters.
*/
public class GeoJsonClusteringActivity extends AppCompatActivity {
@@ -48,11 +45,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_geojson_clustering);
- setupActionBar();
-
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
- //noinspection ConstantConditions
+ // noinspection ConstantConditions
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -61,7 +56,7 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
mapboxMap = map;
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.7749, 122.4194), 0));
- //Add a clustered source with some layers
+ // Add a clustered source with some layers
addClusteredGeoJsonSource();
}
});
@@ -121,7 +116,7 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
}
private void addClusteredGeoJsonSource() {
- //Add a clustered source
+ // Add a clustered source
try {
mapboxMap.addSource(
new GeoJsonSource("earthquakes",
@@ -136,11 +131,11 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
Timber.e("That's not an url... " + malformedUrlException.getMessage());
}
- //Add unclustered layer
+ // Add unclustered layer
int[][] layers = new int[][] {
- new int[] {150, ResourcesCompat.getColor(getResources(), R.color.red_accent, getTheme())},
- new int[] {20, ResourcesCompat.getColor(getResources(), R.color.green_accent, getTheme())},
- new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blue_accent, getTheme())}
+ new int[] {150, ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())},
+ new int[] {20, ResourcesCompat.getColor(getResources(), R.color.greenAccent, getTheme())},
+ new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())}
};
SymbolLayer unclustered = new SymbolLayer("unclustered-points", "earthquakes");
@@ -148,7 +143,7 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
mapboxMap.addLayer(unclustered);
for (int i = 0; i < layers.length; i++) {
- //Add some nice circles
+ // Add some nice circles
CircleLayer circles = new CircleLayer("cluster-" + i, "earthquakes");
circles.setProperties(
circleColor(layers[i][1]),
@@ -162,7 +157,7 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
mapboxMap.addLayer(circles);
}
- //Add the count labels
+ // Add the count labels
SymbolLayer count = new SymbolLayer("count", "earthquakes");
count.setProperties(
textField("{point_count}"),
@@ -172,18 +167,7 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
mapboxMap.addLayer(count);
- //Zoom out to start
+ // Zoom out to start
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(1));
}
-
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java
index fad4f9714d..b9f7ebce35 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RealTimeGeoJsonActivity.java
@@ -3,13 +3,7 @@ package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import timber.log.Timber;
-
-import android.view.MenuItem;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -21,10 +15,12 @@ import com.mapbox.mapboxsdk.testapp.R;
import java.net.MalformedURLException;
import java.net.URL;
+import timber.log.Timber;
+
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
/**
- * Use realtime GeoJSON data streams to move a symbol on your map
+ * Test activity showcasing using realtime GeoJSON to move a symbol on your map
* <p>
* GL-native equivalent of https://www.mapbox.com/mapbox-gl-js/example/live-geojson/
* </p>
@@ -46,15 +42,6 @@ public class RealTimeGeoJsonActivity extends AppCompatActivity implements OnMapR
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_default);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
@@ -119,17 +106,6 @@ public class RealTimeGeoJsonActivity extends AppCompatActivity implements OnMapR
mapView.onSaveInstanceState(outState);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
private static class RefreshGeoJsonRunnable implements Runnable {
private MapboxMap mapboxMap;
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java
index 983f82c53a..af42b7a0fe 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java
@@ -4,9 +4,7 @@ import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.RawRes;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
@@ -16,11 +14,12 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.functions.Function;
+import com.mapbox.mapboxsdk.style.functions.stops.ExponentialStops;
+import com.mapbox.mapboxsdk.style.functions.stops.Stop;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
-import com.mapbox.mapboxsdk.style.layers.Function;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
-import com.mapbox.mapboxsdk.style.layers.NoSuchLayerException;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
@@ -45,13 +44,13 @@ import java.util.List;
import timber.log.Timber;
+import static com.mapbox.mapboxsdk.style.functions.Function.zoom;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.exponential;
import static com.mapbox.mapboxsdk.style.layers.Filter.all;
import static com.mapbox.mapboxsdk.style.layers.Filter.eq;
import static com.mapbox.mapboxsdk.style.layers.Filter.gte;
import static com.mapbox.mapboxsdk.style.layers.Filter.lt;
-import static com.mapbox.mapboxsdk.style.layers.Function.Stop;
-import static com.mapbox.mapboxsdk.style.layers.Function.stop;
-import static com.mapbox.mapboxsdk.style.layers.Function.zoom;
import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP;
import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
import static com.mapbox.mapboxsdk.style.layers.Property.SYMBOL_PLACEMENT_POINT;
@@ -71,7 +70,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
/**
- * Sample Activity to show off the runtime style api
+ * Test activity showcasing the runtime style API.
*/
public class RuntimeStyleActivity extends AppCompatActivity {
@@ -83,9 +82,7 @@ public class RuntimeStyleActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
- setupActionBar();
-
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
@@ -93,10 +90,10 @@ public class RuntimeStyleActivity extends AppCompatActivity {
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(MapboxMap map) {
- //Store for later
+ // Store for later
mapboxMap = map;
- //Center and Zoom (Amsterdam, zoomed to streets)
+ // Center and Zoom (Amsterdam, zoomed to streets)
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
}
});
@@ -153,8 +150,11 @@ public class RuntimeStyleActivity extends AppCompatActivity {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
+ case R.id.action_list_layers:
+ listLayers();
+ return true;
+ case R.id.action_list_sources:
+ listSources();
return true;
case R.id.action_water_color:
setWaterColor();
@@ -203,6 +203,26 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
}
+ private void listLayers() {
+ List<Layer> layers = mapboxMap.getLayers();
+ StringBuilder builder = new StringBuilder("Layers:");
+ for (Layer layer : layers) {
+ builder.append("\n");
+ builder.append(layer.getId());
+ }
+ Toast.makeText(this, builder.toString(), Toast.LENGTH_LONG).show();
+ }
+
+ private void listSources() {
+ List<Source> sources = mapboxMap.getSources();
+ StringBuilder builder = new StringBuilder("Sources:");
+ for (Source source : sources) {
+ builder.append("\n");
+ builder.append(source.getId());
+ }
+ Toast.makeText(this, builder.toString(), Toast.LENGTH_LONG).show();
+ }
+
private void setLayerInvisible() {
String[] roadLayers = new String[] {"water"};
for (String roadLayer : roadLayers) {
@@ -214,7 +234,7 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
private void setRoadSymbolPlacement() {
- //Zoom so that the labels are visible first
+ // Zoom so that the labels are visible first
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(14), new DefaultCallback() {
@Override
public void onFinish() {
@@ -251,16 +271,12 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
private void removeBuildings() {
- //Zoom to see buildings first
- try {
- mapboxMap.removeLayer("building");
- } catch (NoSuchLayerException noSuchLayerException) {
- Toast.makeText(RuntimeStyleActivity.this, noSuchLayerException.getMessage(), Toast.LENGTH_SHORT).show();
- }
+ // Zoom to see buildings first
+ mapboxMap.removeLayer("building");
}
private void addParksLayer() {
- //Add a source
+ // Add a source
Source source;
try {
source = new GeoJsonSource("amsterdam-spots", readRawResource(R.raw.amsterdam));
@@ -282,18 +298,18 @@ public class RuntimeStyleActivity extends AppCompatActivity {
fillAntialias(true)
);
- //Only show me parks (except westerpark with stroke-width == 3)
+ // Only show me parks (except westerpark with stroke-width == 3)
layer.setFilter(all(eq("type", "park"), eq("stroke-width", 2)));
- mapboxMap.addLayer(layer, "building");
- //layer.setPaintProperty(fillColor(Color.RED)); //XXX But not after the object is attached
+ mapboxMap.addLayerBelow(layer, "building");
+ // layer.setPaintProperty(fillColor(Color.RED)); // XXX But not after the object is attached
- //Or get the object later and set it. It's all good.
+ // Or get the object later and set it. It's all good.
mapboxMap.getLayer("parksLayer").setProperties(fillColor(Color.RED));
- //You can get a typed layer, if you're sure it's of that type. Use with care
+ // You can get a typed layer, if you're sure it's of that type. Use with care
layer = mapboxMap.getLayerAs("parksLayer");
- //And get some properties
+ // And get some properties
PropertyValue<Boolean> fillAntialias = layer.getFillAntialias();
Timber.d("Fill anti alias: " + fillAntialias.getValue());
layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
@@ -302,12 +318,12 @@ public class RuntimeStyleActivity extends AppCompatActivity {
PropertyValue<String> visibility = layer.getVisibility();
Timber.d("Visibility: " + visibility.getValue());
- //Get a good look at it all
+ // Get a good look at it all
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12));
}
private void addDynamicParksLayer() {
- //Load some data
+ // Load some data
FeatureCollection parks;
try {
String json = readRawResource(R.raw.amsterdam);
@@ -321,7 +337,7 @@ public class RuntimeStyleActivity extends AppCompatActivity {
return;
}
- //Add an empty source
+ // Add an empty source
mapboxMap.addSource(new GeoJsonSource("dynamic-park-source"));
FillLayer layer = new FillLayer("dynamic-parks-layer", "dynamic-park-source");
@@ -332,15 +348,15 @@ public class RuntimeStyleActivity extends AppCompatActivity {
fillAntialias(true)
);
- //Only show me parks
+ // Only show me parks
layer.setFilter(all(eq("type", "park")));
mapboxMap.addLayer(layer);
- //Get a good look at it all
+ // Get a good look at it all
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12));
- //Animate the parks source
+ // Animate the parks source
animateParksSource(parks, 0);
}
@@ -354,7 +370,7 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
Timber.d("Updating parks source");
- //change the source
+ // change the source
int park = counter < parks.getFeatures().size() - 1 ? counter : 0;
GeoJsonSource source = mapboxMap.getSourceAs("dynamic-park-source");
@@ -369,14 +385,14 @@ public class RuntimeStyleActivity extends AppCompatActivity {
features.add(parks.getFeatures().get(park));
source.setGeoJson(FeatureCollection.fromFeatures(features));
- //Re-post
+ // Re-post
animateParksSource(parks, park + 1);
}
}, counter == 0 ? 100 : 1000);
}
private void addTerrainLayer() {
- //Add a source
+ // Add a source
Source source = new VectorSource("my-terrain-source", "mapbox://mapbox.mapbox-terrain-v2");
mapboxMap.addSource(source);
@@ -391,10 +407,10 @@ public class RuntimeStyleActivity extends AppCompatActivity {
mapboxMap.addLayer(layer);
- //Need to get a fresh handle
+ // Need to get a fresh handle
layer = mapboxMap.getLayerAs("terrainLayer");
- //Make sure it's also applied after the fact
+ // Make sure it's also applied after the fact
layer.setMinZoom(10);
layer.setMaxZoom(15);
@@ -404,11 +420,11 @@ public class RuntimeStyleActivity extends AppCompatActivity {
}
private void addSatelliteLayer() {
- //Add a source
+ // Add a source
Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite", 512);
mapboxMap.addSource(source);
- //Add a layer
+ // Add a layer
mapboxMap.addLayer(new RasterLayer("satellite-layer", "my-raster-source"));
}
@@ -418,24 +434,29 @@ public class RuntimeStyleActivity extends AppCompatActivity {
return;
}
- //Set a zoom function to update the color of the water
- layer.setProperties(fillColor(zoom(0.8f,
- stop(1, fillColor(Color.GREEN)),
- stop(4, fillColor(Color.BLUE)),
- stop(12, fillColor(Color.RED)),
- stop(20, fillColor(Color.BLACK))
- )));
-
- //do some animations to show it off properly
+ // Set a zoom function to update the color of the water
+ layer.setProperties(fillColor(
+ zoom(
+ exponential(
+ stop(1, fillColor(Color.GREEN)),
+ stop(4, fillColor(Color.BLUE)),
+ stop(12, fillColor(Color.RED)),
+ stop(20, fillColor(Color.BLACK))
+ ).withBase(0.8f)
+ )
+ ));
+
+ // do some animations to show it off properly
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(1), 1500);
PropertyValue<String> fillColor = layer.getFillColor();
- Function<String> function = fillColor.getFunction();
+ Function<Float, String> function = (Function<Float, String>) fillColor.getFunction();
if (function != null) {
- Timber.d("Fill color base: " + function.getBase());
- Timber.d("Fill color #stops: " + function.getStops().length);
+ ExponentialStops<Float, String> stops = (ExponentialStops) function.getStops();
+ Timber.d("Fill color base: " + stops.getBase());
+ Timber.d("Fill color #stops: " + stops.size());
if (function.getStops() != null) {
- for (Stop stop : function.getStops()) {
+ for (Stop<Float, String> stop : stops) {
Timber.d("Fill color #stops: " + stop);
}
}
@@ -459,23 +480,12 @@ public class RuntimeStyleActivity extends AppCompatActivity {
return writer.toString();
}
- private void setupActionBar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
-
private void addCustomTileSource() {
- //Add a source
+ // Add a source
Source source = new VectorSource("custom-tile-source", new TileSet("2.1.0", "https://vector.mapzen.com/osm/all/{z}/{x}/{y}.mvt?api_key=vector-tiles-LM25tq4"));
mapboxMap.addSource(source);
- //Add a layer
+ // Add a layer
mapboxMap.addLayer(
new FillLayer("custom-tile-layers", "custom-tile-source")
.withSourceLayer("water")
@@ -577,12 +587,12 @@ public class RuntimeStyleActivity extends AppCompatActivity {
@Override
public void onCancel() {
- //noop
+ // noop
}
@Override
public void onFinish() {
- //noop
+ // noop
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java
index 1d242359bc..910233accf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTestActivity.java
@@ -9,7 +9,7 @@ import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
/**
- * Test activity for unit test execution
+ * Test activity used for instrumentation test execution.
*/
public class RuntimeStyleTestActivity extends AppCompatActivity {
@@ -21,7 +21,7 @@ public class RuntimeStyleTestActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java
index c57bc0069a..5057578731 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleTimingTestActivity.java
@@ -29,7 +29,7 @@ public class RuntimeStyleTimingTestActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
- //Initialize map as normal
+ // Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java
index 73e6bc985a..6906e90f6e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/StyleFileActivity.java
@@ -6,10 +6,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.RawRes;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -32,7 +29,7 @@ import java.io.Writer;
import timber.log.Timber;
/**
- * Example on how to use a file:// resource for the style.json
+ * Test activity showcasing how to use a file:// resource for the style.json
*/
public class StyleFileActivity extends AppCompatActivity {
@@ -44,15 +41,6 @@ public class StyleFileActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style_file);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -93,7 +81,7 @@ public class StyleFileActivity extends AppCompatActivity {
}
protected void onPostExecute(Long result) {
- //Actual file:// usage
+ // Actual file:// usage
mapboxMap.setStyleUrl("file://" + cacheStyleFile.getAbsolutePath());
}
@@ -168,15 +156,4 @@ public class StyleFileActivity extends AppCompatActivity {
super.onDestroy();
mapView.onDestroy();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
index be71e58eba..82da905413 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java
@@ -5,9 +5,7 @@ import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
@@ -37,7 +35,7 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
- * Example to test runtime manipulation of symbol layers
+ * Test activity showcasing runtime manipulation of symbol layers.
*/
public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener {
@@ -51,15 +49,6 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_symbollayer);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -67,21 +56,21 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
- //Add a image for the makers
+ // Add a image for the makers
mapboxMap.addImage(
"my-marker-image",
BitmapFactory.decodeResource(SymbolLayerActivity.this.getResources(),
R.drawable.mapbox_marker_icon_default)
);
- //Add a source
+ // Add a source
FeatureCollection markers = FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(Point.fromCoordinates(new double[] {4.91638, 52.35673}), featureProperties("Marker 1")),
Feature.fromGeometry(Point.fromCoordinates(new double[] {4.91638, 52.34673}), featureProperties("Marker 2"))
});
mapboxMap.addSource(new GeoJsonSource(MARKER_SOURCE, markers));
- //Add the symbol-layer
+ // Add the symbol-layer
mapboxMap.addLayer(
new SymbolLayer(MARKER_LAYER, MARKER_SOURCE)
.withProperties(
@@ -93,10 +82,10 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
)
);
- //Show
+ // Show
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.35273, 4.91638), 14));
- //Set a click-listener so we can manipulate the map
+ // Set a click-listener so we can manipulate the map
mapboxMap.setOnMapClickListener(SymbolLayerActivity.this);
}
});
@@ -104,13 +93,13 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
@Override
public void onMapClick(@NonNull LatLng point) {
- //Query which features are clicked
+ // Query which features are clicked
PointF screenLoc = mapboxMap.getProjection().toScreenLocation(point);
List<Feature> features = mapboxMap.queryRenderedFeatures(screenLoc, MARKER_LAYER);
SymbolLayer layer = mapboxMap.getLayerAs(MARKER_LAYER);
if (features.size() == 0) {
- //Reset
+ // Reset
layer.setProperties(iconSize(1f));
} else {
layer.setProperties(iconSize(3f));
@@ -195,9 +184,6 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
case R.id.action_toggle_text_size:
toggleTextSize();
return true;
@@ -211,5 +197,4 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.
return super.onOptionsItemSelected(item);
}
}
-
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
index e20455b1ce..d31bd1fa51 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationDrawableActivity.java
@@ -9,25 +9,25 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
-public class MyLocationDrawableActivity extends AppCompatActivity implements LocationListener {
+/**
+ * Test activity showcasing how to change the MyLocationView drawable.
+ */
+public class MyLocationDrawableActivity extends AppCompatActivity implements LocationEngineListener {
private static final int PERMISSIONS_LOCATION = 0;
@@ -38,14 +38,6 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_location_customization);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
findViewById(R.id.progress).setVisibility(View.GONE);
@@ -53,8 +45,8 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
mapboxMapOptions.styleUrl(Style.MAPBOX_STREETS);
// configure MyLocationView drawables
- mapboxMapOptions.myLocationForegroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_chelsea));
- mapboxMapOptions.myLocationBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_arsenal));
+ mapboxMapOptions.myLocationForegroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android));
+ mapboxMapOptions.myLocationBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.ic_android));
mapboxMapOptions.myLocationForegroundTintColor(Color.GREEN);
mapboxMapOptions.myLocationBackgroundTintColor(Color.YELLOW);
mapboxMapOptions.myLocationBackgroundPadding(new int[] {0, 0,
@@ -103,7 +95,7 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
if (location != null) {
onLocationChanged(location);
} else {
- LocationServices.getLocationServices(this).addLocationListener(this);
+ LocationSource.getLocationEngine(this).addLocationEngineListener(this);
}
} else {
mapboxMap.setMyLocationEnabled(false);
@@ -120,6 +112,11 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
}
@Override
+ public void onConnected() {
+ // Nothing
+ }
+
+ @Override
public void onLocationChanged(Location location) {
if (mapboxMap != null) {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 14));
@@ -167,16 +164,4 @@ public class MyLocationDrawableActivity extends AppCompatActivity implements Loc
super.onLowMemory();
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
index 2da3bedcbf..0417b1829f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTintActivity.java
@@ -12,25 +12,25 @@ import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.location.LocationListener;
-import com.mapbox.mapboxsdk.location.LocationServices;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
-public class MyLocationTintActivity extends AppCompatActivity implements LocationListener {
+/**
+ * Test activity showcasing how to tint the MyLocationView.
+ */
+public class MyLocationTintActivity extends AppCompatActivity implements LocationEngineListener {
private MapView mapView;
private MapboxMap mapboxMap;
@@ -43,15 +43,6 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_location_dot_color);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
-
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(new OnMapReadyCallback() {
@@ -94,9 +85,9 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
@Override
public void onClick(View view) {
myLocationViewSettings.setAccuracyTintColor(
- ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapbox_green));
+ ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapboxGreen));
myLocationViewSettings.setForegroundTintColor(
- ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapbox_green));
+ ContextCompat.getColor(MyLocationTintActivity.this, R.color.mapboxGreen));
myLocationViewSettings.setBackgroundTintColor(Color.WHITE);
}
});
@@ -133,6 +124,11 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
}
@Override
+ public void onConnected() {
+ // Nothing
+ }
+
+ @Override
public void onLocationChanged(Location location) {
if (mapboxMap != null && firstRun) {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 15));
@@ -144,7 +140,7 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
protected void onStart() {
super.onStart();
mapView.onStart();
- LocationServices.getLocationServices(this).addLocationListener(this);
+ LocationSource.getLocationEngine(this).addLocationEngineListener(this);
}
@Override
@@ -162,7 +158,7 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
@Override
protected void onStop() {
super.onStop();
- LocationServices.getLocationServices(this).removeLocationListener(this);
+ LocationSource.getLocationEngine(this).removeLocationEngineListener(this);
mapView.onStop();
}
@@ -184,17 +180,6 @@ public class MyLocationTintActivity extends AppCompatActivity implements Locatio
mapView.onSaveInstanceState(outState);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
@UiThread
public void toggleGps(boolean enableGps) {
if (enableGps) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
index e522840038..9e98d8c6b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationToggleActivity.java
@@ -5,23 +5,22 @@ import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
import android.view.View;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
public class MyLocationToggleActivity extends AppCompatActivity {
@@ -29,6 +28,9 @@ public class MyLocationToggleActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
private FloatingActionButton locationToggleFab;
+ private LocationEngine locationServices;
+ private LocationEngineListener locationListener;
+
private static final int PERMISSIONS_LOCATION = 0;
@Override
@@ -36,15 +38,7 @@ public class MyLocationToggleActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_location_toggle);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayShowTitleEnabled(true);
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
+ locationServices = LocationSource.getLocationEngine(this);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
@@ -100,6 +94,11 @@ public class MyLocationToggleActivity extends AppCompatActivity {
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
+ // Ensure no memory leak occurs if we register the location listener but the call hasn't
+ // been made yet.
+ if (locationListener != null) {
+ locationServices.removeLocationEngineListener(locationListener);
+ }
}
@Override
@@ -108,27 +107,11 @@ public class MyLocationToggleActivity extends AppCompatActivity {
mapView.onLowMemory();
}
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
- onBackPressed();
- return true;
- default:
- return false;
- }
- }
-
@UiThread
public void toggleGps(boolean enableGps) {
if (enableGps) {
- if ((ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
- || (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- ActivityCompat.requestPermissions(this, new String[] {
- Manifest.permission.ACCESS_COARSE_LOCATION,
+ if (!PermissionsManager.areLocationPermissionsGranted(this)) {
+ ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
} else {
enableLocation(true);
@@ -140,25 +123,37 @@ public class MyLocationToggleActivity extends AppCompatActivity {
private void enableLocation(boolean enabled) {
if (enabled) {
- mapboxMap.setOnMyLocationChangeListener(new MapboxMap.OnMyLocationChangeListener() {
- @Override
- public void onMyLocationChange(@Nullable Location location) {
- if (location != null) {
- mapboxMap.setCameraPosition(new CameraPosition.Builder()
- .target(new LatLng(location))
- .zoom(16)
- .bearing(0)
- .tilt(0)
- .build());
- mapboxMap.setOnMyLocationChangeListener(null);
- }
+ // To move the camera instantly, we attempt to get the last known location and either
+ // ease or animate the camera to that position depending on the zoom level.
+ Location lastLocation = LocationSource.getLocationEngine(this).getLastLocation();
+
+ if (lastLocation != null) {
+ if (mapboxMap.getCameraPosition().zoom > 15.99) {
+ mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(lastLocation)), 1000);
+ } else {
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lastLocation), 16), 1000);
}
- });
- locationToggleFab.setImageResource(R.drawable.ic_location_disabled_24dp);
+ } else {
+ locationListener = new LocationEngineListener() {
+ @Override
+ public void onConnected() {
+ // Nothing
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ if (location != null) {
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location), 16));
+ locationServices.removeLocationEngineListener(this);
+ }
+ }
+ };
+ locationServices.addLocationEngineListener(locationListener);
+ }
+ locationToggleFab.setImageResource(R.drawable.ic_location_disabled);
} else {
- locationToggleFab.setImageResource(R.drawable.ic_my_location_24dp);
+ locationToggleFab.setImageResource(R.drawable.ic_my_location);
}
-
mapboxMap.setMyLocationEnabled(enabled);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
index 3d08399abf..3a3301b87f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/userlocation/MyLocationTrackingModeActivity.java
@@ -1,15 +1,7 @@
package com.mapbox.mapboxsdk.testapp.activity.userlocation;
-import android.Manifest;
-import android.content.pm.PackageManager;
-import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
@@ -21,11 +13,8 @@ import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -33,20 +22,26 @@ import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
-public class MyLocationTrackingModeActivity extends AppCompatActivity
- implements MapboxMap.OnMyLocationChangeListener, AdapterView.OnItemSelectedListener {
+/**
+ * Test activity showcasing the different tracking modes the SDK exposes.
+ * <p>
+ * This includes MyLocationTracking/MyLocationBearingTracking and how the components can be configured to be dismissed
+ * using gesture configurations.
+ * </p>
+ */
+public class MyLocationTrackingModeActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
public static final int TRACKING_NONE_INDEX = 0;
public static final int TRACKING_FOLLOW_INDEX = 1;
public static final int BEARING_NONE_INDEX = 0;
public static final int BEARING_GPS_INDEX = 1;
public static final int BEARING_COMPASS_INDEX = 2;
+
private MapView mapView;
private MapboxMap mapboxMap;
private Spinner locationSpinner;
private Spinner bearingSpinner;
- private Location location;
- private static final int PERMISSIONS_LOCATION = 0;
+
private MenuItem dismissLocationTrackingOnGestureItem;
private MenuItem dismissBearingTrackingOnGestureItem;
private MenuItem enableRotateGesturesItem;
@@ -91,8 +86,6 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity
bearingSpinner.setOnItemSelectedListener(MyLocationTrackingModeActivity.this);
setCheckBoxes();
- mapboxMap.setOnMyLocationChangeListener(MyLocationTrackingModeActivity.this);
-
mapboxMap.setOnMyLocationTrackingModeChangeListener(new MapboxMap.OnMyLocationTrackingModeChangeListener() {
@Override
public void onMyLocationTrackingModeChange(@MyLocationTracking.Mode int myLocationTrackingMode) {
@@ -131,91 +124,12 @@ public class MyLocationTrackingModeActivity extends AppCompatActivity
});
if (savedInstanceState == null) {
- toggleGps(true);
+ mapboxMap.setMyLocationEnabled(true);
}
}
});
}
- @UiThread
- public void toggleGps(boolean enableGps) {
- if (enableGps) {
- if ((ContextCompat.checkSelfPermission(this,
- Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
- || (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- ActivityCompat.requestPermissions(this, new String[] {
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
- } else {
- enableLocation(true);
- }
- } else {
- enableLocation(false);
- }
- }
-
- private void enableLocation(boolean enabled) {
- if (enabled) {
- mapboxMap.setMyLocationEnabled(true);
- Location location = mapboxMap.getMyLocation();
- if (location != null) {
- setInitialPosition(new LatLng(location));
- }
- } else {
- mapboxMap.setMyLocationEnabled(false);
- }
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- if (requestCode == PERMISSIONS_LOCATION) {
- if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- enableLocation(true);
- }
- }
- }
-
- private void setInitialPosition(LatLng latLng) {
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14));
- mapboxMap.setMyLocationEnabled(true);
- locationSpinner.setEnabled(true);
- bearingSpinner.setEnabled(true);
- }
-
- @Override
- public void onMyLocationChange(@Nullable Location location) {
- if (location != null) {
- if (this.location == null) {
- // initial location to reposition map
- setInitialPosition(new LatLng(location));
- }
- this.location = location;
- showSnackBar();
- }
- }
-
- private void showSnackBar() {
- String desc = "Loc Chg: ";
- boolean noInfo = true;
- if (location.hasSpeed()) {
- desc += String.format(MapboxConstants.MAPBOX_LOCALE, "Spd = %.1f km/h ", location.getSpeed() * 3.6f);
- noInfo = false;
- }
- if (location.hasAltitude()) {
- desc += String.format(MapboxConstants.MAPBOX_LOCALE, "Alt = %.0f m ", location.getAltitude());
- noInfo = false;
- }
- if (location.hasAccuracy()) {
- desc += String.format(MapboxConstants.MAPBOX_LOCALE, "Acc = %.0f m", location.getAccuracy());
- }
-
- if (noInfo) {
- desc += "No extra info";
- }
- Snackbar.make(findViewById(android.R.id.content), desc, Snackbar.LENGTH_SHORT).show();
- }
-
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) throws SecurityException {
TrackingSettings trackingSettings = mapboxMap.getTrackingSettings();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java
index a935c2134f..7ac3401a0d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureAdapter.java
@@ -13,6 +13,12 @@ import com.mapbox.mapboxsdk.testapp.utils.FontCache;
import java.util.List;
+/**
+ * Adapter used for FeatureOverviewActivity.
+ * <p>
+ * Adapts a Feature to a visual representation to be shown in a RecyclerView.
+ * </p>
+ */
public class FeatureAdapter extends RecyclerView.Adapter<FeatureAdapter.ViewHolder> {
private List<Feature> features;
@@ -52,4 +58,4 @@ public class FeatureAdapter extends RecyclerView.Adapter<FeatureAdapter.ViewHold
public int getItemCount() {
return features.size();
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java
index 012bbed4ca..1d89f89f08 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/adapter/FeatureSectionAdapter.java
@@ -91,7 +91,8 @@ public class FeatureSectionAdapter extends RecyclerView.Adapter<RecyclerView.Vie
@Override
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
if (isSectionHeaderPosition(position)) {
- ((SectionViewHolder) sectionViewHolder).title.setText(sections.get(position).title);
+ String cleanTitle = sections.get(position).title.toString().replace("_", " ");
+ ((SectionViewHolder) sectionViewHolder).title.setText(cleanTitle);
} else {
adapter.onBindViewHolder(sectionViewHolder, getConvertedPosition(position));
}
@@ -176,4 +177,4 @@ public class FeatureSectionAdapter extends RecyclerView.Adapter<RecyclerView.Vie
return (valid ? adapter.getItemCount() + sections.size() : 0);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java
index 3b9f67aa1e..15b2f0b127 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CityStateMarker.java
@@ -15,4 +15,4 @@ public class CityStateMarker extends Marker {
return infoWindowBackgroundColor;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java
index af97c9df69..6b172ef83f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarker.java
@@ -21,4 +21,4 @@ public class CountryMarker extends Marker {
public int getFlagRes() {
return flagRes;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
index 4dc9195ffd..6602054f47 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/CountryMarkerViewOptions.java
@@ -96,4 +96,4 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions<CountryMarke
return new CountryMarkerViewOptions[size];
}
};
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java
index 971c3359b2..b01c9907e0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java
@@ -8,4 +8,4 @@ public class PulseMarkerView extends MarkerView {
public PulseMarkerView(BaseMarkerViewOptions baseMarkerViewOptions) {
super(baseMarkerViewOptions);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java
index 20c479fc9b..d9c6357774 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java
@@ -76,4 +76,4 @@ public class PulseMarkerViewOptions extends BaseMarkerViewOptions<PulseMarkerVie
return new CountryMarkerViewOptions[size];
}
};
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java
index f507c5f1ab..dcee5c2409 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/TextMarkerView.java
@@ -15,4 +15,4 @@ public class TextMarkerView extends MarkerView {
public String getText() {
return text;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java
index b70144123f..c4aa934139 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineDownloadRegionDialog.java
@@ -37,7 +37,7 @@ public class OfflineDownloadRegionDialog extends DialogFragment {
final EditText regionNameEdit = new EditText(getActivity());
builder.setTitle("Choose a name for the region")
- .setIcon(R.drawable.ic_airplanemode_active_black_24dp)
+ .setIcon(R.drawable.ic_airplanemode_active_black)
.setView(regionNameEdit)
.setPositiveButton("Start", new DialogInterface.OnClickListener() {
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java
index 65c4102a8c..f717daeada 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/other/OfflineListRegionsDialog.java
@@ -28,7 +28,7 @@ public class OfflineListRegionsDialog extends DialogFragment {
CharSequence[] items = offlineRegionsNames.toArray(new CharSequence[offlineRegionsNames.size()]);
builder.setTitle("List of offline regions")
- .setIcon(R.drawable.ic_airplanemode_active_black_24dp)
+ .setIcon(R.drawable.ic_airplanemode_active_black)
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java
index e2271bd5ff..10ecf43bd3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/FontCache.java
@@ -23,4 +23,4 @@ public class FontCache {
}
return tf;
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java
new file mode 100644
index 0000000000..b6768a91a3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IconUtils.java
@@ -0,0 +1,31 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+
+public class IconUtils {
+
+ /**
+ * Demonstrates converting any Drawable to an Icon, for use as a marker icon.
+ */
+ public static Icon drawableToIcon(@NonNull Context context, @DrawableRes int id, @ColorInt int colorRes) {
+ Drawable vectorDrawable = ResourcesCompat.getDrawable(context.getResources(), id, context.getTheme());
+ Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
+ vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ DrawableCompat.setTint(vectorDrawable, colorRes);
+ vectorDrawable.draw(canvas);
+ return IconFactory.getInstance(context).fromBitmap(bitmap);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java
index 414a781544..0939181ef4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ItemClickSupport.java
@@ -92,4 +92,4 @@ public class ItemClickSupport {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View view);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java
index e096aa202d..6f20d6fb0f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TimingLogger.java
@@ -106,7 +106,7 @@ public class TimingLogger {
* dumpToLog call will do nothing.
*/
public void reset() {
- disabled = false; //!Log.isLoggable(tag, Log.VERBOSE);
+ disabled = false; // !Log.isLoggable(tag, Log.VERBOSE);
if (disabled) {
return;
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ToolbarComposer.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ToolbarComposer.java
deleted file mode 100644
index 3fa3bcd26f..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/ToolbarComposer.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.utils;
-
-import android.support.annotation.IdRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-
-import com.mapbox.mapboxsdk.testapp.R;
-
-/**
- * Helper class to compose a Toolbar in an AppCompatActivity
- */
-public class ToolbarComposer {
-
-
- /**
- * Initialises an up navigation toolbar with id R.id.toolbar on an AppCompatActivity.
- *
- * @param activity The activity hosting the Toolbar with id R.id.toolbar
- */
- @Nullable
- public static Toolbar initDefaultUpToolbar(@NonNull AppCompatActivity activity) {
- return initDefaultUpToolbar(activity, R.id.toolbar);
- }
-
- /**
- * Initialises an up navigation toolbar given a view id on an AppCompatActivity.
- *
- * @param activity The activity hosting the Toolbar
- * @param toolbarRes The view id resource used to look up the Toolbar
- */
- @Nullable
- public static Toolbar initDefaultUpToolbar(@NonNull AppCompatActivity activity, @IdRes int toolbarRes) {
- Toolbar toolbar = (Toolbar) activity.findViewById(toolbarRes);
- if (toolbar != null) {
- activity.setSupportActionBar(toolbar);
-
- ActionBar actionBar = activity.getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowHomeEnabled(true);
- }
- }
- return toolbar;
- }
-
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml
deleted file mode 100644
index 40bc57ab68..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:interpolator="@android:anim/decelerate_interpolator">
-
- <scale
- android:duration="1000"
- android:fromXScale="1"
- android:fromYScale="1"
- android:pivotX="50%"
- android:pivotY="50%"
- android:repeatCount="infinite"
- android:repeatMode="restart"
- android:toXScale="1.8"
- android:toYScale="1.8"/>
-
- <set android:startOffset="200">
- <alpha
- android:duration="800"
- android:fromAlpha="1.0"
- android:repeatCount="infinite"
- android:repeatMode="restart"
- android:toAlpha="0.0"/>
- </set>
-</set> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/rotate_360.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/rotate_360.xml
deleted file mode 100644
index e3569966d2..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/rotate_360.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set xmlns:android="http://schemas.android.com/apk/res/android">
- <objectAnimator
- android:propertyName="rotation"
- android:valueFrom="0"
- android:valueTo="360"
- android:valueType="floatType"/>
-</set> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml
index d1067b09c2..f450edb1fb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_down.xml
@@ -8,4 +8,4 @@
android:propertyName="scaleY"
android:duration="300"
android:valueTo="1"/>
-</set> \ No newline at end of file
+</set>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml
index b43ed05513..f8da05f35e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/animator/scale_up.xml
@@ -8,4 +8,4 @@
android:propertyName="scaleY"
android:duration="300"
android:valueTo="2"/>
-</set> \ No newline at end of file
+</set>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android.png
new file mode 100644
index 0000000000..a20277dc1b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android_2.png
new file mode 100644
index 0000000000..d1c802c265
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_android_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png
deleted file mode 100644
index c59f601ca3..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-hdpi/ic_drawer.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android.png
new file mode 100644
index 0000000000..114bb25199
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android_2.png
new file mode 100644
index 0000000000..62867cdca4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_android_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png
deleted file mode 100644
index 1ed2c56ee4..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/ic_drawer.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android.png
new file mode 100644
index 0000000000..e80400c4dd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android_2.png
new file mode 100644
index 0000000000..1b34d09842
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_android_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png
deleted file mode 100644
index a5fa74def4..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xhdpi/ic_drawer.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android.png
new file mode 100644
index 0000000000..19be40bf88
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android_2.png
new file mode 100644
index 0000000000..b44cec791f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_android_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png
deleted file mode 100644
index 6fdac4ef09..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_arsenal.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png
deleted file mode 100644
index 6cd376b281..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_chelsea.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png
deleted file mode 100644
index 9c4685d6e0..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxhdpi/ic_drawer.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android.png
new file mode 100644
index 0000000000..c2c4373973
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android_2.png
new file mode 100644
index 0000000000..b735fda69f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_android_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top_small.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top_small.png
deleted file mode 100644
index e04c199160..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top_small.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add.xml
index 6cdfce3074..6cdfce3074 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black.xml
index 3d2ba42f3e..3d2ba42f3e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_add_a_photo_black.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black.xml
index 55a8d22a54..55a8d22a54 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_airplanemode_active_black.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml
index 006b2ce5a8..3217661b64 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml
@@ -9,4 +9,4 @@
<size
android:width="@dimen/circle_size"
android:height="@dimen/circle_size"/>
-</shape> \ No newline at end of file
+</shape>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml
deleted file mode 100644
index 1e2d044bee..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FFFFFF"
- android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
-</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete.xml
index f0e8643c35..f0e8643c35 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_delete.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black.xml
index e16e259792..e16e259792 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_bus_black.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black.xml
index 6d6337c3ab..6d6337c3ab 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black.xml
index dfa43f020e..dfa43f020e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin.xml
index a25e7884cd..a25e7884cd 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_droppin.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input.xml
index fea69dfb79..fea69dfb79 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_input.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers.xml
index 944b526c5c..944b526c5c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear.xml
index 249f57fc65..249f57fc65 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_layers_clear.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city.xml
index e9bea94b41..e9bea94b41 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_city.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml
index 4fedff778b..4fedff778b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_location_disabled.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location.xml
index eb979016bf..eb979016bf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_my_location.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print.xml
index 7a9bc00287..7a9bc00287 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_print.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh.xml
index 20cd9a07d8..20cd9a07d8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh_24dp.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_refresh.xml
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_stars.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_stars.xml
new file mode 100644
index 0000000000..61c5d7ace2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_stars.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM16.23,18L12,15.45 7.77,18l1.12,-4.81 -3.73,-3.23 4.92,-0.42L12,5l1.92,4.53 4.92,0.42 -3.73,3.23L16.23,18z"/>
+</vector>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml
index 2dc6b4a008..c301b9b6f4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/line_divider.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1dp"
- android:height="1dp" />
+ android:height="1dp"/>
- <solid android:color="@android:color/darker_gray" />
+ <solid android:color="@android:color/darker_gray"/>
-</shape> \ No newline at end of file
+</shape>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/marker.xml
new file mode 100644
index 0000000000..71992ebd7f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/marker.xml
@@ -0,0 +1,4 @@
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <size android:width="10px" android:height="10px"/>
+ <solid android:color="@color/redAccent"/>
+</shape> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_remove_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_remove_marker.xml
index 596f52aab1..6da5a61ecb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_remove_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_remove_marker.xml
@@ -1,19 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml
index e0e2cbfdab..00dc67ebed 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_add_sprite.xml
@@ -1,26 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
- android:layout_below="@id/toolbar"
android:layout_width="match_parent"
+ android:layout_height="match_parent"
app:mapbox_cameraTargetLat="52.519003"
app:mapbox_cameraTargetLng="13.400972"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
app:mapbox_cameraZoom="16"
- android:layout_height="match_parent"/>
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
<android.support.design.widget.FloatingActionButton
android:id="@id/fab"
@@ -30,7 +23,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_add_24dp"
- app:backgroundTint="@android:color/white" />
+ android:src="@drawable/ic_add"
+ app:backgroundTint="@android:color/white"/>
</RelativeLayout>
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 6534c23c72..0566757d58 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
@@ -1,25 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/toolbar"
app:mapbox_cameraTargetLat="51.502615"
app:mapbox_cameraTargetLng="4.972326"
- app:mapbox_styleUrl="@string/mapbox_style_light"
- app:mapbox_cameraZoom="6" />
+ app:mapbox_cameraZoom="6"
+ app:mapbox_styleUrl="@string/mapbox_style_light"/>
-</RelativeLayout>
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml
index 8a139083f8..b70bb6d7b2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_animation_types.xml
@@ -1,25 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/toolbar"
app:mapbox_cameraTargetLat="51.50325"
app:mapbox_cameraTargetLng="-0.11968"
- app:mapbox_cameraZoom="15" />
+ app:mapbox_cameraZoom="15"/>
<LinearLayout
android:layout_width="match_parent"
@@ -33,21 +26,21 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="@string/button_camera_move" />
+ android:text="@string/button_camera_move"/>
<Button
android:id="@+id/cameraEaseButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="@string/button_camera_ease" />
+ android:text="@string/button_camera_ease"/>
<Button
android:id="@+id/cameraAnimateButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="@string/button_camera_animate" />
+ android:text="@string/button_camera_animate"/>
</LinearLayout>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
index a1d7a8351d..341218c406 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
@@ -1,36 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_input_24dp"
- app:backgroundTint="@android:color/white" />
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_input"
+ app:backgroundTint="@android:color/white"/>
- </android.support.design.widget.CoordinatorLayout>
-</LinearLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml
index 4f86120097..05affaf081 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_test.xml
@@ -1,22 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<!-- TODO remove zoom #6747-->
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
- app:mapbox_cameraZoom="1" />
+ app:mapbox_cameraZoom="1"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_car_driving.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_car_driving.xml
deleted file mode 100644
index f52d5e70c2..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_car_driving.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@+id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_myLocationTintColor="@color/primary"
- app:mapbox_myLocationAccuracyTintColor="@color/primary"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="15" />
-
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
index 4aecf36c71..8a21bef8a8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circle_layer.xml
@@ -30,7 +30,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_directions_bus_black_24dp"
+ android:src="@drawable/ic_directions_bus_black"
app:backgroundTint="@android:color/white" />
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circlelayer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circlelayer.xml
deleted file mode 100644
index e0e2cbfdab..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_circlelayer.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_below="@id/toolbar"
- android:layout_width="match_parent"
- app:mapbox_cameraTargetLat="52.519003"
- app:mapbox_cameraTargetLng="13.400972"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="16"
- android:layout_height="match_parent"/>
-
- <android.support.design.widget.FloatingActionButton
- android:id="@id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_add_24dp"
- app:backgroundTint="@android:color/white" />
-
-</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml
index 247d10bf86..800926f894 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_custom_layer.xml
@@ -1,45 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
+ android:layout_height="match_parent"/>
- </android.support.v7.widget.Toolbar>
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_layers"
+ app:backgroundTint="@android:color/white"/>
- <FrameLayout
- android:id="@+id/content_frame"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_layers_24dp"
- app:backgroundTint="@android:color/white" />
-
- </android.support.design.widget.CoordinatorLayout>
-
- </FrameLayout>
+</android.support.design.widget.CoordinatorLayout>
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_data_driven_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_data_driven_style.xml
new file mode 100644
index 0000000000..7454ce5860
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_data_driven_style.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml
index 36adfbc6e9..ffbf2e30a1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_debug_mode.xml
@@ -1,57 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
-
- </android.support.v7.widget.Toolbar>
-
- <FrameLayout
- android:id="@+id/content_frame"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@+id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
-
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@+id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fabDebug"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_marginBottom="82dp"
- android:layout_marginRight="@dimen/fab_margin"
- android:src="@drawable/ic_refresh_24dp"
- app:backgroundTint="@color/accent"
- app:layout_anchorGravity="top" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fabStyles"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_layers_24dp"
- app:backgroundTint="@color/primary" />
-
- </android.support.design.widget.CoordinatorLayout>
-
- </FrameLayout>
-
-</LinearLayout>
+ android:layout_height="match_parent"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabDebug"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_marginBottom="82dp"
+ android:layout_marginRight="@dimen/fab_margin"
+ android:src="@drawable/ic_refresh"
+ app:backgroundTint="@color/accent"
+ app:layout_anchorGravity="top"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabStyles"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_layers"
+ app:backgroundTint="@color/primary"/>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml
index 742f6612bd..f292c80267 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_default.xml
@@ -1,19 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar" />
+ android:layout_height="match_parent"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml
deleted file mode 100644
index bc100b6059..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_directions.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@+id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" />
-
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml
index 2625e65bbf..e119d3cf7c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_dynamic_marker.xml
@@ -1,51 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <FrameLayout
- android:id="@+id/content_frame"
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/toolbar">
-
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_cameraTargetLat="51.506675"
- app:mapbox_cameraTargetLng="-0.128699"
- app:mapbox_uiCompassFadeFacingNorth="false"
- app:mapbox_cameraBearing="90"
- app:mapbox_cameraTilt="40"
- app:mapbox_cameraZoom="10" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_animate_coordinates"
- app:backgroundTint="@color/white" />
-
- </android.support.design.widget.CoordinatorLayout>
-
- </FrameLayout>
-
-</RelativeLayout>
-
-
+ app:mapbox_cameraBearing="90"
+ app:mapbox_cameraTargetLat="51.506675"
+ app:mapbox_cameraTargetLng="-0.128699"
+ app:mapbox_cameraTilt="40"
+ app:mapbox_cameraZoom="10"
+ app:mapbox_uiCompassFadeFacingNorth="false"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_animate_coordinates"
+ app:backgroundTint="@color/white"/>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml
new file mode 100644
index 0000000000..28b23b633d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_feature_overview.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/recyclerView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbars="vertical"/>
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml
deleted file mode 100644
index d13d16a73e..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geocoder.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="5"
- app:mapbox_cameraTargetLat="38.90962"
- app:mapbox_cameraTargetLng="-77.04341"
- app:mapbox_cameraZoom="15" />
-
- <TextView
- android:id="@+id/message"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1"
- android:gravity="center" />
-
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml
index 4c0d067c14..f292c80267 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_geojson_clustering.xml
@@ -1,19 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar"/>
+ android:layout_height="match_parent"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
index 1c8e33fb33..3339341f6e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow.xml
@@ -1,24 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:mapbox_cameraTargetLat="38.897705003219784"
app:mapbox_cameraTargetLng="-77.03655168667463"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="15" />
+ app:mapbox_cameraZoom="15"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
index 134c3f331e..abb41c05c4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter.xml
@@ -1,24 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:mapbox_cameraTargetLat="47.798202"
app:mapbox_cameraTargetLng="7.573781"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="4" />
+ app:mapbox_cameraZoom="4"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml
deleted file mode 100644
index 134c3f331e..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_cameraTargetLat="47.798202"
- app:mapbox_cameraTargetLng="7.573781"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="4" />
-
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml
deleted file mode 100644
index f6a89c0149..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar" />
-
- <ImageButton
- android:id="@+id/clearDisplayViewButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_above="@+id/selectLocationButton"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginLeft="@dimen/full_button_margin"
- android:background="@color/accent"
- android:src="@drawable/ic_clear_24dp"
- android:visibility="gone" />
-
- <Button
- android:id="@+id/selectLocationButton"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_margin="@dimen/full_button_margin"
- android:background="@color/primary"
- android:text="@string/navigation_select_location_button_text"
- android:textColor="@android:color/white" />
-
-</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_source.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_source.xml
deleted file mode 100644
index a1d7a8351d..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_source.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_input_24dp"
- app:backgroundTint="@android:color/white" />
-
- </android.support.design.widget.CoordinatorLayout>
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 41956385f9..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <android.support.v7.widget.RecyclerView
- android:id="@+id/recyclerView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scrollbars="vertical" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml
index 3732326f39..d533762857 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_manual_zoom.xml
@@ -1,25 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
- app:mapbox_cameraTargetLat="50.871062"
- app:mapbox_cameraTargetLng="1.583210"
- app:mapbox_cameraBearing="220"
- app:mapbox_cameraZoom="10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/toolbar" />
+ android:layout_below="@id/toolbar"
+ app:mapbox_cameraBearing="220"
+ app:mapbox_cameraTargetLat="50.871062"
+ app:mapbox_cameraTargetLng="1.583210"
+ app:mapbox_cameraZoom="10"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml
index a421f21ede..43fa8fb995 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_fragment.xml
@@ -1,22 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activity.fragment.MapFragmentActivity">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml
index 1edc456252..3fd66977e2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_in_dialog.xml
@@ -4,13 +4,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<Button
android:id="@+id/button_open_dialog"
android:layout_width="wrap_content"
@@ -18,4 +11,4 @@
android:layout_gravity="center"
android:text="@string/button_open_dialog"/>
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml
index cd61fef44b..a0de31ee48 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_padding.xml
@@ -12,7 +12,6 @@
<View
android:layout_width="@dimen/map_padding_left"
android:layout_height="match_parent"
- android:layout_marginTop="?attr/actionBarSize"
android:alpha="0.5"
android:background="@color/mapbox_blue" />
@@ -27,19 +26,10 @@
android:alpha="0.5"
android:background="@color/mapbox_blue" />
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:alpha="0.5"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<View
android:layout_width="@dimen/map_padding_right"
android:layout_height="match_parent"
android:layout_gravity="end"
- android:layout_marginTop="?attr/actionBarSize"
android:alpha="0.5"
android:background="@color/mapbox_blue" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml
index 4ad49e4a9f..96a3f5b046 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_map_simple.xml
@@ -1,19 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
+ android:orientation="vertical"
+ tools:context=".activity.maplayout.SimpleMapActivity">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
index 229d8e87c1..ff28d2edf0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_bulk.xml
@@ -1,32 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
-
- <Spinner
- android:id="@+id/spinner"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- </android.support.v7.widget.Toolbar>
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:mapbox_cameraTargetLat="38.87031"
android:layout_below="@id/toolbar"
+ app:mapbox_cameraTargetLat="38.87031"
app:mapbox_cameraTargetLng="-77.00897"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="10" />
+ app:mapbox_cameraZoom="10"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
<TextView
android:id="@+id/countView"
@@ -45,6 +32,6 @@
android:layout_alignParentRight="true"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_animate_coordinates" />
+ android:src="@drawable/ic_animate_coordinates"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view.xml
index f06975466b..cf4b51bbe0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view.xml
@@ -1,16 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
@@ -25,7 +19,6 @@
android:id="@+id/countView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_below="@id/toolbar"
android:padding="16dp"
android:textSize="20sp" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_in_rect.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_in_rect.xml
index 36dd89c885..ecda2873ce 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_in_rect.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_in_rect.xml
@@ -4,18 +4,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar"/>
+ android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/selection_box"
@@ -23,6 +15,6 @@
android:layout_height="150dp"
android:layout_centerInParent="true"
android:alpha="0.3"
- android:background="#1d72da"/>
+ android:background="@color/mapboxGreen"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml
deleted file mode 100644
index 8f98b5bea2..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_marker_view_scale.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="8dp">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:paddingBottom="8dp"
- android:textSize="20sp"
- android:textColor="#FFFFFF"
- android:text="Scaling in the View Marker API" />
-
- <TextView
- android:id="@+id/textview_factor"
- android:layout_alignBottom="@+id/seekbar_factor"
- android:layout_below="@id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Scale: 1" />
-
- <SeekBar
- android:id="@+id/seekbar_factor"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/title"
- android:clickable="false"
- android:layout_marginLeft="56dp"
- android:progress="0" />
-
- </RelativeLayout>
-
-
- </android.support.v7.widget.Toolbar>
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar"
- app:mapbox_cameraTargetLat="38.907192"
- app:mapbox_cameraTargetLng="-77.036871"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="12" />
-
-</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml
index 20de7c00bf..4428100e41 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_maxmin_zoom.xml
@@ -1,25 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/toolbar"
app:mapbox_cameraTargetLat="-1.063510"
app:mapbox_cameraTargetLng=" 32.895425"
- app:mapbox_styleUrl="@string/mapbox_style_satellite_streets"
- app:mapbox_cameraZoom="4" />
+ app:mapbox_cameraZoom="4"
+ app:mapbox_styleUrl="@string/mapbox_style_satellite_streets"/>
</RelativeLayout>
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 067a52dae4..084675fb2c 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,20 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"/>
<TextView
android:id="@android:id/empty"
@@ -22,6 +16,6 @@
android:layout_height="match_parent"
android:gravity="center"
android:text="No Results"
- android:textSize="24sp" />
+ android:textSize="24sp"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
index f8046a8821..0b3fd9acdf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_multi_map.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/tools"
android:id="@+id/map_container"
android:layout_width="match_parent"
@@ -23,7 +24,7 @@
mapbox:center_latitude="38.913187"
mapbox:center_longitude="-77.032546"
mapbox:style_url="mapbox://styles/mapbox/streets-v9"
- mapbox:zoom="12" />
+ mapbox:zoom="12"/>
<!-- SF -->
<fragment
@@ -35,7 +36,7 @@
mapbox:center_latitude="37.775732"
mapbox:center_longitude="-122.413985"
mapbox:style_url="mapbox://styles/mapbox/outdoors-v9"
- mapbox:zoom="13" />
+ mapbox:zoom="13"/>
</LinearLayout>
<LinearLayout
@@ -55,7 +56,7 @@
mapbox:center_latitude="12.97913"
mapbox:center_longitude="77.59188"
mapbox:style_url="mapbox://styles/mapbox/light-v9"
- mapbox:zoom="14" />
+ mapbox:zoom="14"/>
<!-- Ayacucho -->
<fragment
@@ -67,6 +68,6 @@
mapbox:center_latitude="-13.155980"
mapbox:center_longitude="-74.217134"
mapbox:style_url="mapbox://styles/mapbox/dark-v9"
- mapbox:zoom="15" />
+ mapbox:zoom="15"/>
</LinearLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml
index 262128703f..d65d5796f1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_customization.xml
@@ -1,17 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<FrameLayout
android:id="@id/progress"
android:layout_width="match_parent"
@@ -21,7 +15,7 @@
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center" />
+ android:layout_gravity="center"/>
</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml
index d41cc79326..de18e265de 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_dot_color.xml
@@ -1,23 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:mapbox="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/toolbar"
mapbox:mapbox_uiAttribution="false"
mapbox:mapbox_uiLogo="false"/>
@@ -68,4 +59,4 @@
</LinearLayout>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml
index 8ca01ef411..2ec35faf04 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_my_location_toggle.xml
@@ -1,36 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:id="@id/coordinator_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent"/>
- <android.support.design.widget.CoordinatorLayout
- android:id="@id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fabLocationToggle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_my_location_24dp"
- tools:backgroundTint="@color/primary" />
-
- </android.support.design.widget.CoordinatorLayout>
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabLocationToggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_my_location"
+ tools:backgroundTint="@color/primary"/>
-</LinearLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml
index 2bf08fbdc1..26a71bc568 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_navigation_drawer.xml
@@ -30,4 +30,4 @@
android:layout_gravity="start"
android:fitsSystemWindows="true" />
-</android.support.v4.widget.DrawerLayout> \ No newline at end of file
+</android.support.v4.widget.DrawerLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml
index 434cb59115..d4b64b1ea2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline.xml
@@ -1,52 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="25dp"
- android:layout_below="@+id/toolbar"
android:indeterminate="true"
- android:visibility="gone" />
+ android:visibility="gone"/>
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/progress_bar" />
+ android:layout_below="@+id/progress_bar"/>
<Button
+ android:id="@+id/button_download_region"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="10dp"
- android:text="@string/button_download_region"
- android:id="@+id/button_download_region"
- android:layout_margin="@dimen/fab_margin"
+ android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
- android:layout_alignParentBottom="true"
- android:background="@color/white"/>
+ android:layout_margin="@dimen/fab_margin"
+ android:background="@color/white"
+ android:padding="10dp"
+ android:text="@string/button_download_region"/>
<Button
+ android:id="@+id/button_list_regions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:padding="10dp"
- android:text="@string/button_list_regions"
- android:id="@+id/button_list_regions"
android:layout_alignBottom="@+id/button_download_region"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/fab_margin"
- android:background="@color/white"/>
+ android:background="@color/white"
+ android:padding="10dp"
+ android:text="@string/button_list_regions"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml
new file mode 100644
index 0000000000..084675fb2c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_offline_region_delete.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@+id/listView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
+ <TextView
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:text="No Results"
+ android:textSize="24sp"/>
+
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polygon.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polygon.xml
deleted file mode 100644
index 1c60deb328..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polygon.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
-</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
index d856676260..3f8c384b3f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_polyline.xml
@@ -1,22 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/toolbar"
app:mapbox_uiAttributionTintColor="@android:color/holo_green_dark"
app:mapbox_cameraTargetLat="47.798202"
app:mapbox_cameraTargetLng="7.573781"
@@ -32,7 +24,7 @@
android:layout_alignParentRight="true"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_add_24dp"
+ android:src="@drawable/ic_add"
app:backgroundTint="@android:color/white" />
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
index f5a9a17917..9932803907 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_press_for_marker.xml
@@ -1,28 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
- app:mapbox_uiAttributionGravity="top|end"
app:mapbox_cameraTargetLat="45.1855569"
app:mapbox_cameraTargetLng="5.7215506"
- app:mapbox_uiLogoGravity="top|end"
- app:mapbox_uiLogoMarginRight="10dp"
+ app:mapbox_cameraZoom="11"
app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
- app:mapbox_cameraZoom="11" />
+ app:mapbox_uiAttributionGravity="top|end"
+ app:mapbox_uiLogoGravity="top|end"
+ app:mapbox_uiLogoMarginRight="10dp"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml
index 76451f5918..3ff8caea70 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_print.xml
@@ -1,45 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<android.support.design.widget.CoordinatorLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
+ <com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
-
- </android.support.v7.widget.Toolbar>
-
- <FrameLayout
- android:id="@+id/content_frame"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <android.support.design.widget.CoordinatorLayout
- android:id="@+id/coordinator_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
- <android.support.design.widget.FloatingActionButton
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_print_24dp"
- app:backgroundTint="@color/accent" />
-
- </android.support.design.widget.CoordinatorLayout>
-
- </FrameLayout>
-
-</LinearLayout>
+ android:layout_height="match_parent"/>
+
+ <android.support.design.widget.FloatingActionButton
+ android:id="@+id/fab"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="end|bottom"
+ android:layout_margin="@dimen/fab_margin"
+ android:src="@drawable/ic_print"
+ app:backgroundTint="@color/accent"/>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml
index dfd067cec7..3ddd7d64b4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_box.xml
@@ -1,16 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
@@ -18,7 +12,7 @@
android:layout_below="@id/toolbar"
app:mapbox_cameraTargetLat="52.0907"
app:mapbox_cameraTargetLng="5.1214"
- app:mapbox_cameraZoom="16" />
+ app:mapbox_cameraZoom="16"/>
<FrameLayout
android:id="@+id/selection_box"
@@ -26,6 +20,6 @@
android:layout_height="150dp"
android:layout_centerInParent="true"
android:alpha="0.3"
- android:background="#1d72da" />
+ android:background="@color/mapboxGreen"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml
index 6889a5fac1..66750dc47e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_query_features_point.xml
@@ -1,23 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@id/toolbar"
app:mapbox_cameraTargetLat="52.0907"
app:mapbox_cameraTargetLng="5.1214"
- app:mapbox_cameraZoom="16" />
+ app:mapbox_cameraZoom="16"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml
index 34823b0da1..7454ce5860 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_runtime_style.xml
@@ -1,19 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar" />
+ android:layout_height="match_parent"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml
index 46734ed82d..bc24533960 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_scroll_by.xml
@@ -91,7 +91,7 @@
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_input_24dp"
+ android:src="@drawable/ic_input"
app:backgroundTint="@color/white" />
</android.support.design.widget.CoordinatorLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
index ac69780592..6b99711e84 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml
@@ -1,21 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@+id/toolbar"
android:orientation="vertical">
<ImageView
@@ -23,7 +16,7 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:background="@color/primary" />
+ android:background="@color/primary"/>
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
@@ -41,7 +34,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_add_a_photo_black_24dp"
- app:backgroundTint="@android:color/white" />
+ android:src="@drawable/ic_add_a_photo_black"
+ app:backgroundTint="@android:color/white"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml
index e0e2cbfdab..b133f3d9a5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_style_file.xml
@@ -1,26 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
- android:layout_below="@id/toolbar"
android:layout_width="match_parent"
+ android:layout_height="match_parent"
app:mapbox_cameraTargetLat="52.519003"
app:mapbox_cameraTargetLng="13.400972"
- app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"
app:mapbox_cameraZoom="16"
- android:layout_height="match_parent"/>
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
<android.support.design.widget.FloatingActionButton
android:id="@id/fab"
@@ -30,7 +22,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_margin="@dimen/fab_margin"
- android:src="@drawable/ic_add_24dp"
- app:backgroundTint="@android:color/white" />
+ android:src="@drawable/ic_add"
+ app:backgroundTint="@android:color/white"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml
deleted file mode 100644
index 364e86adda..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_surfaceview_mediacontrols.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/toolbar"
- app:mapbox_styleUrl="@string/mapbox_style_light" />
-
- <FrameLayout
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="128dp"
- android:layout_alignParentBottom="true"
- android:paddingBottom="48dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp" />
-
-</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml
index 67892abbd1..9b88994f1c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml
@@ -1,22 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_below="@id/toolbar"
app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_video_view.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_video_view.xml
deleted file mode 100644
index b640f9f878..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_video_view.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:mapbox="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".activity.maplayout.VideoViewActivity">
-
- <android.support.v7.widget.Toolbar
- android:id="@id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
- <VideoView
- android:id="@+id/video_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_margin="16dp" />
-
- <com.mapbox.mapboxsdk.maps.MapView
- android:id="@id/mapView"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar"
- mapbox:mapbox_uiAttributionGravity="top"
- mapbox:mapbox_cameraTargetLat="34.4021"
- mapbox:mapbox_cameraTargetLng="-119.7081"
- mapbox:mapbox_uiLogoGravity="top"
- mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v9"
- mapbox:mapbox_cameraZoom="13" />
-
-</RelativeLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
index 9bb5560bb2..d931cb3643 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml
@@ -1,21 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
+ android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/toolbar">
+ android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="@+id/viewpager_header"
@@ -23,8 +15,8 @@
android:layout_height="wrap_content"
android:layout_gravity="top"
android:paddingBottom="4dp"
- android:paddingTop="4dp" />
+ android:paddingTop="4dp"/>
</android.support.v4.view.ViewPager>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_visible_bounds.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_visible_bounds.xml
index 17a5c27942..89a28a7799 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_visible_bounds.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_visible_bounds.xml
@@ -1,19 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="@color/primary"
- android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
-
<com.mapbox.mapboxsdk.maps.MapView
android:id="@id/mapView"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml
index c1ffa7d203..1c9fbbd482 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/dialog_camera_position.xml
@@ -199,4 +199,4 @@
</RelativeLayout>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
index b40ad1273d..8241d0264f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/fragment_dialog_map.xml
@@ -15,4 +15,4 @@
mapbox:mapbox_renderTextureMode="true"
mapbox:mapbox_styleUrl="mapbox://styles/mapbox/streets-v9" />
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml
index 93af094e3f..b290d013f0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_main_feature.xml
@@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical"
+ android:paddingEnd="16dp"
android:paddingLeft="16dp"
+ android:paddingRight="16dp"
android:paddingStart="16dp"
android:paddingTop="16dp">
@@ -12,24 +15,22 @@
android:id="@+id/nameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:text="Dummy headline"
- android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
- android:singleLine="true"
+ android:layout_marginRight="16dp"
+ android:gravity="center_vertical"
+ android:maxLines="1"
android:textColor="@android:color/black"
- android:textSize="16sp" />
+ android:textSize="16sp"/>
<TextView
android:id="@+id/descriptionView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:alpha="0.56"
- android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
- android:singleLine="true"
- android:text="Description is dummy dummy"
+ android:layout_marginRight="16dp"
+ android:alpha="0.56"
+ android:maxLines="1"
android:textColor="@android:color/black"
- android:textSize="14sp" />
+ android:textSize="14sp"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml
index 8978d4e3eb..75f6ac9588 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/section_main_layout.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp">
@@ -7,21 +8,21 @@
android:layout_width="match_parent"
android:layout_height="0.25dp"
android:alpha="0.56"
- android:background="@drawable/line_divider" />
+ android:background="@drawable/line_divider"/>
<TextView
android:id="@+id/section_text"
android:layout_width="match_parent"
android:layout_height="48dp"
+ android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
+ android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
- android:layout_marginRight="16dp"
- android:layout_marginEnd="16dp"
android:alpha="0.54"
android:background="@android:color/transparent"
- android:singleLine="true"
+ android:maxLines="1"
android:textColor="@android:color/black"
- android:textSize="14sp" />
+ android:textSize="14sp"/>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
index 98050c061f..c2bbdae775 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_custom_marker.xml
@@ -18,4 +18,4 @@
android:layout_centerHorizontal="true"
android:padding="2dp"/>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml
deleted file mode 100644
index e1ac50b440..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="48dp"
- android:layout_height="48dp">
-
- <ImageView
- android:id="@+id/foreground_imageView"
- android:layout_width="@dimen/circle_size"
- android:layout_height="@dimen/circle_size"
- android:layout_gravity="center"
- android:src="@drawable/ic_circle"/>
-
- <ImageView
- android:id="@+id/background_imageview"
- android:layout_width="@dimen/circle_size"
- android:layout_height="@dimen/circle_size"
- android:layout_gravity="center"
- android:alpha="0.5"
- android:src="@drawable/ic_circle"/>
-
-</FrameLayout> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml
index 8a3508691a..299865be9e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_text_marker.xml
@@ -2,7 +2,7 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@color/mapbox_green">
+ android:background="@color/mapboxGreen">
<TextView
android:id="@id/textView"
@@ -13,4 +13,4 @@
android:padding="4dp"
android:layout_centerInParent="true" />
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bulk_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bulk_marker.xml
new file mode 100644
index 0000000000..8b7245c5ca
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_bulk_marker.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/spinner"
+ android:title="Amount of markers"
+ app:actionViewClass="android.widget.Spinner"
+ app:showAsAction="always"/>
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml
index ec1f756333..4639dd65ba 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_custom_layer.xml
@@ -14,4 +14,4 @@
<item
android:id="@+id/action_set_color_blue"
android:title="Blue" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_data_driven_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_data_driven_style.xml
new file mode 100644
index 0000000000..3eae56a273
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_data_driven_style.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:mapbox="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/action_add_exponential_zoom_function"
+ android:title="Add an exponential zoom function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_interval_zoom_function"
+ android:title="Add an interval zoom function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_categorical_source_function"
+ android:title="Add a categorical source function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_exponential_source_function"
+ android:title="Add an exponential source function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_identity_source_function"
+ android:title="Add an identity source function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_interval_source_function"
+ android:title="Add an interval source function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_composite_exponential_function"
+ android:title="Add a composite, exponential function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_composite_categorical_function"
+ android:title="Add a composite, categorical function"
+ mapbox:showAsAction="never"/>
+
+ <item
+ android:id="@+id/action_add_composite_interval_function"
+ android:title="Add a composite, interval function"
+ mapbox:showAsAction="never"/>
+
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
index adca8d2e00..3dc705dbb9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml
@@ -16,4 +16,4 @@
android:checked="true"/>
</group>
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml
deleted file mode 100644
index 2c5178af08..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"></menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml
index 0db887c4e7..e0052d4a8c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_padding.xml
@@ -9,4 +9,4 @@
android:id="@+id/action_bangalore"
android:title="Bangalore"
mapbox:showAsAction="never" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
index 62d4c83594..a7fdf56be5 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polygon.xml
@@ -17,4 +17,4 @@
android:id="@+id/action_id_color"
android:title="@string/action_color_polygon"
mapbox:showAsAction="never" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
index 7c324fc9dc..8549d66042 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_polyline.xml
@@ -3,7 +3,7 @@
xmlns:mapbox="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_id_remove"
- android:icon="@drawable/ic_delete_24dp"
+ android:icon="@drawable/ic_delete"
android:title="@string/action_remove_polylines"
mapbox:showAsAction="ifRoom" />
<item
@@ -22,4 +22,4 @@
android:id="@+id/action_id_visible"
android:title="@string/action_visibility_polygon"
mapbox:showAsAction="never" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml
index 18f09db82a..86f0b4faee 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml
@@ -3,6 +3,14 @@
xmlns:mapbox="http://schemas.android.com/apk/res-auto">
<item
+ android:id="@+id/action_list_layers"
+ android:title="List all layers in the style"
+ mapbox:showAsAction="never" />
+ <item
+ android:id="@+id/action_list_sources"
+ android:title="List all sources in the style"
+ mapbox:showAsAction="never" />
+ <item
android:id="@+id/action_water_color"
android:title="Color the water"
mapbox:showAsAction="never" />
@@ -58,4 +66,4 @@
android:id="@+id/action_numeric_filter"
android:title="Apply numeric fill filter"
mapbox:showAsAction="never" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml
index e6fd1fce45..77468b4861 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_symbol_layer.xml
@@ -13,4 +13,4 @@
android:id="@+id/action_toggle_text_font"
android:title="Toggle text font"/>
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml
index 91424d3f5b..940dd9c461 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_tracking.xml
@@ -29,4 +29,4 @@
app:showAsAction="never" />
</group>
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml
index 5cec70afb6..0cea519a24 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_zoom.xml
@@ -22,4 +22,4 @@
android:title="Zoom to 4"
mapbox:showAsAction="never" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson
index c5585533a0..e433a509eb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/amsterdam.geojson
@@ -256,7 +256,7 @@
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#555555",
- "fill-opacity": 0.5,
+ "fill-opacity": 1.0,
"name": "Sarphatipark",
"type": "park",
"description": "Sarphatipark is a small park in the popular De Pijp neighbourhood. It was openend in late 19th century, and named after Samuel Sarphati."
@@ -482,7 +482,7 @@
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#555555",
- "fill-opacity": 0.5,
+ "fill-opacity": 0.1,
"name": "Sloterdijk",
"type": "area",
"description": "To protect the area around Sloten from the as-yet undrained IJ the Spaarndammerdijk was laid along the south bank of this inlet. In this vicinity at the same time, a dam on the Slochter (or Slooter) river was built, the Slooterdam. Trade grew in the vicinity, and in the 15th century a weigh house and a church were built. The area is nowadays best known as a large intersection of train lines and a business and industrial centre north-west of Amsterdam."
@@ -574,7 +574,7 @@
"stroke-width": 2,
"stroke-opacity": 1,
"fill": "#555555",
- "fill-opacity": 0.5,
+ "fill-opacity": 0.7,
"name": "Artis",
"type": "poi",
"description": "Artis, short for Natura Artis Magistra (Latin for \"Nature is the teacher of art and science\"), is a zoo in the centre of Amsterdam. It is the oldest zoo in the Netherlands and one of the oldest zoos of mainland Europe. Artis Royal Zoo is not just a zoo, it also contains an aquarium and a planetarium. Artis also has an arboretum and a fairly large art collection. A part of the art collection is on display in the Aquarium building of the zoo. Artis contains 27 monumental buildings, most of which are used as enclosures for the animals, making Artis a unique cultural heritage of the 19th century."
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/sea_waves.mp4 b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/sea_waves.mp4
deleted file mode 100644
index ac2bcae016..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/sea_waves.mp4
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml
index 2eb503b057..944f563f2f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/attrs.xml
@@ -3,4 +3,4 @@
<declare-styleable name="ScrimInsetsView">
<attr name="appInsetForeground" format="reference|color" />
</declare-styleable>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml
deleted file mode 100644
index 035b9f3564..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/dimens.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <dimen name="toolbar_padding_top">25dp</dimen>
-</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml
index 3d61b9a36d..ab690c664c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-v21/styles.xml
@@ -3,17 +3,17 @@
<style name="AppTheme" parent="AppBaseTheme">
- </style>r
+ </style>
- <style name="AppTheme.ActionBar.Transparent" parent="AppTheme">
+ <style name="AppTheme.ActionBar.Transparent" parent="NoActionBar">
<item name="colorPrimary">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
<style name="AppTheme.ActionBar" parent="AppTheme">
- <item name="colorPrimaryDark">@color/primary_dark</item>
+ <item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorPrimary">@color/primary</item>
</style>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml
deleted file mode 100644
index 63fc816444..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values-w820dp/dimens.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<resources>
- <!-- Example customization of dimensions originally defined in res/values/dimens.xml
- (such as screen margins) for screens with more than 820dp of available width. This
- would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
- <dimen name="activity_horizontal_margin">64dp</dimen>
-</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
new file mode 100644
index 0000000000..94763342d2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string-array name="bulk_marker_list">
+ <item>10</item>
+ <item>100</item>
+ <item>500</item>
+ <item>1000</item>
+ <item>10000</item>
+ </string-array>
+
+ <string-array name="user_tracking_mode">
+ <item>Disabled</item>
+ <item>Follow tracking</item>
+ </string-array>
+
+ <string-array name="user_bearing_mode">
+ <item>Disabled</item>
+ <item>GPS bearing</item>
+ <item>Compass bearing</item>
+ <!--<item>Combined mode</item>-->
+ </string-array>
+</resources> \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml
index 78fc76af1c..88524d44ea 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/colors.xml
@@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <color name="primary">#1E8CAB</color>
- <color name="primary_dark">#166B83</color>
+ <color name="primary">#52A1D8</color>
+ <color name="primaryDark">#3887BE</color>
<color name="accent">#E55E5E</color>
<color name="white">#F9F9F9</color>
- <color name="mapbox_green">#56B881</color>
+ <color name="mapboxGreen">#56B881</color>
+
+ <color name="redAccent">#D50000</color>
+ <color name="blueAccent">#2962FF</color>
+ <color name="greenAccent">#1B5E20</color>
- <color name="red_accent">#D50000</color>
- <color name="blue_accent">#2962FF</color>
- <color name="green_accent">#1B5E20</color>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
index b77a25b681..402d42d485 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/dimens.xml
@@ -2,18 +2,12 @@
<resources>
<dimen name="circle_size">24dp</dimen>
<dimen name="fab_margin">16dp</dimen>
- <dimen name="full_button_margin">8dp</dimen>
<dimen name="attr_margin">10dp</dimen>
<dimen name="coordinatebounds_margin">32dp</dimen>
<dimen name="map_padding_left">96dp</dimen>
<dimen name="map_padding_bottom">256dp</dimen>
<dimen name="map_padding_right">32dp</dimen>
- <dimen name="toolbar_shadow">4dp</dimen>
+ <dimen name="map_padding_top">0dp</dimen>
<dimen name="locationview_background_drawable_padding">2dp</dimen>
- <dimen name="locationview_padding_top">350dp</dimen>
- <!-- Default screen margins, per the Android Design guidelines. -->
- <dimen name="activity_horizontal_margin">16dp</dimen>
- <dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="navigation_drawer_width">240dp</dimen>
- <dimen name="toolbar_padding_top">0dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml
index 120bf49fca..6701032d97 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/ids.xml
@@ -8,4 +8,4 @@
<item name="toolbar" type="id" />
<item name="container" type="id" />
<item name="item_click_support" type="id" />
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index 53688cdf35..61d251f861 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -1,50 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
-
<string name="app_name">Mapbox Android SDK TestApp</string>
- <!-- Test Activities -->
- <string name="activity_mapboxmap">MapboxMap Activity</string>
-
- <!-- Fragment -->
+ <!--Activity-->
<string name="activity_map_fragment_suport">Support Map Fragment</string>
<string name="activity_map_fragment">Map Fragment</string>
<string name="activity_multimap">Multiple Maps on Screen</string>
-
- <!-- Annotations -->
<string name="activity_add_bulk_markers">Add Markers In Bulk</string>
- <string name="activity_animated_marker">Animated Marker (experimental)</string>
+ <string name="activity_animated_marker">Animated Markers</string>
<string name="activity_dynamic_marker">Dynamic Marker</string>
<string name="activity_polyline">Polyline</string>
<string name="activity_polygon">Polygon</string>
<string name="activity_press_for_marker">Press Map For Marker</string>
<string name="activity_view_marker">View Marker API</string>
- <string name="activity_view_marker_scale">Scaling in the View Marker API</string>
<string name="activity_add_remove_markers">Add/Remove marker</string>
-
- <!-- InfoWindow-->
<string name="activity_info_window">Standard InfoWindow</string>
<string name="activity_infowindow_adapter">Custom InfoWindow</string>
<string name="activity_dynamic_infowindow_adapter">Custom Dynamic InfoWindow</string>
-
- <!-- Camera -->
<string name="activity_camera_animation_types">Animation Types</string>
<string name="activity_camera_zoom">Zoom Methods</string>
<string name="activity_visible_coordinate_bounds">LatLngBounds Method</string>
<string name="activity_camera_position">CameraPosition Method</string>
<string name="activity_scroll_by">Scroll By Method</string>
-
- <!-- API -->
- <string name="activity_directions">Directions</string>
- <string name="activity_geocoder">Geocoder</string>
-
- <!-- Navigation -->
- <string name="activity_location_picker">Location Picker</string>
- <string name="activity_car_driving">Driving animation</string>
-
- <!-- Other -->
<string name="activity_double_map">Double Map Activity</string>
- <string name="activity_back_to_map">Back to map activity</string>
<string name="activity_snapshot">Snapshot Activity</string>
<string name="activity_user_tracking_mode">User tracking mode</string>
<string name="activity_user_tracking_customization">User location drawable</string>
@@ -55,9 +33,11 @@
<string name="activity_debug_mode">Debug Mode</string>
<string name="activity_offline">Offline Map</string>
<string name="activity_update_metadata">Update metadata Map</string>
+ <string name="activity_offline_region_delete">Delete region</string>
<string name="activity_minmax_zoom">Min/Max Zoom</string>
<string name="activity_viewpager">ViewPager</string>
<string name="activity_runtime_style">Runtime Style</string>
+ <string name="activity_data_driven_style">Data Driven Style</string>
<string name="activity_circle_layer">Circle layer</string>
<string name="activity_style_file">Local Style file</string>
<string name="activity_geojson_clustering">GeoJson Clustering</string>
@@ -74,7 +54,7 @@
<string name="activity_map_in_dialog">Dialog with map</string>
<string name="activity_marker_view_rectangle">Marker views in rectangle</string>
- <!-- Description -->
+ <!--Description-->
<string name="description_user_location_tracking">Tracks the location of the user</string>
<string name="description_user_location_customization">Customize the location of the user</string>
<string name="description_user_location_dot_color">Customize the user location color</string>
@@ -89,7 +69,6 @@
<string name="description_camera_zoom">Different types of zoom methods</string>
<string name="description_minmax_zoom">Configure a max and min zoomlevel</string>
<string name="description_info_window">Learn how to handle the InfoWindow</string>
- <string name="description_info_window_concurrent">InfoWindow example with multiple open</string>
<string name="description_add_bulk_markers">Add Markers In Bulk to a Map</string>
<string name="description_camera_animation_types">Showcase the different animation types</string>
<string name="description_visible_bounds">Center the camera around a bounds</string>
@@ -98,21 +77,18 @@
<string name="description_debug_mode">Debug Mode</string>
<string name="description_offline">Offline Map example</string>
<string name="description_update_metadata">Update metadata example</string>
- <string name="description_animated_marker">Animate the position change of a Marker</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_polyline">Add a polyline to a map</string>
<string name="description_polygon">Add a polygon to a map</string>
- <string name="description_directions">Example with Directions API</string>
- <string name="description_geocoder">Example with Geocoder API</string>
<string name="description_scroll_by">Scroll with pixels in x,y direction</string>
<string name="description_snapshot">Example to make a snapshot of the map</string>
<string name="description_doublemap">2 maps in a view hierarchy</string>
- <string name="description_back_to_map">Restart map view after temporarily leaving to another activity</string>
<string name="description_view_marker">Use an Android SDK View as marker</string>
- <string name="description_view_marker_scale">Scale a View Marker</string>
<string name="description_dynamic_info_window_adapter">Learn how to create a dynamic custom InfoWindow</string>
- <string name="description_location_picker">Use a fixed Marker to select your location</string>
<string name="description_viewpager">Use SupportMapFragments in a ViewPager</string>
<string name="description_runtime_style">Adopt the map style on the fly</string>
+ <string name="description_data_driven_style">Use functions to change the map appearance</string>
<string name="description_symbol_layer">Manipulate symbols at runtime</string>
<string name="description_custom_sprite">Use a custom sprite in a Symbol Layer</string>
<string name="description_geojson_clustering">Use GeoJson sources and dynamic layers to cluster information</string>
@@ -123,7 +99,6 @@
<string name="description_query_rendered_features_box_count">Count all rendered features in box</string>
<string name="description_query_rendered_features_box_symbol_count">Count all rendered symbols in box</string>
<string name="description_query_rendered_features_box_highlight">Hightligh buildings in box</string>
- <string name="description_car_driving">MyLocationView follow map update example</string>
<string name="description_simple_map">Shows a simple map</string>
<string name="description_add_remove_markers">Based on zoom level</string>
<string name="description_style_file">Use a local file as the style</string>
@@ -131,109 +106,58 @@
<string name="description_marker_view_rectangle">Marker Views within a rectangle</string>
<string name="description_circle_layer">Show bus stops and route in Singapore</string>
- <string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>
- <string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string>
- <string name="menuitem_title_tracking_mode_dismiss_on_gesture">Dismiss location tracking on gesture</string>
- <string name="menuitem_title_bearing_mode_dismiss_on_gesture">Dismiss bearing tracking on gesture</string>
- <string name="menuitem_title_reset">Reset</string>
-
+ <!--Categories-->
<string name="category">category</string>
+ <string name="category_basic">_Basic</string>
<string name="category_annotation">Annotation</string>
<string name="category_camera">Camera</string>
<string name="category_custom_layer">Custom Layer</string>
- <string name="category_directions">Directions</string>
<string name="category_fragment">Fragment</string>
- <string name="category_geocoding">Geocoding</string>
<string name="category_imagegenerator">Image Generator</string>
- <string name="category_infowindow">InfoWindow</string>
+ <string name="category_infowindow">Info Window</string>
<string name="category_maplayout">Map Layout</string>
<string name="category_offline">Offline</string>
<string name="category_userlocation">User Location</string>
- <string name="category_navigation">Navigation</string>
<string name="category_style">Styling</string>
<string name="category_features">Features</string>
- <string name="action_visible_bounds_explanation">Center map around 2 markers</string>
+ <!--Actions-->
<string name="action_remove_polylines">Remove polylines</string>
-
<string name="action_visibility_polygon">Change visibility</string>
<string name="action_alpha_polygon">Change alpha</string>
<string name="action_points_polygon">Change points</string>
<string name="action_color_polygon">Change color</string>
<string name="action_width_polyline">Change width</string>
+ <!--Menu-->
+ <string name="menuitem_title_concurrent_infowindow">Concurrent Open InfoWindows</string>
+ <string name="menuitem_title_deselect_markers_on_tap">Deselect Markers On Tap</string>
+ <string name="menuitem_title_tracking_mode_dismiss_on_gesture">Dismiss location tracking on gesture</string>
+ <string name="menuitem_title_bearing_mode_dismiss_on_gesture">Dismiss bearing tracking on gesture</string>
+ <string name="menuitem_title_reset">Reset</string>
+ <string name="menuitem_title_rotate_gesture_enabled">Enable rotate gestures</string>
+ <string name="menuitem_title_scroll_gesture_enabled">Enable scroll gestures</string>
+
+ <!--Button-->
<string name="button_camera_move">Move</string>
<string name="button_camera_ease">Ease</string>
<string name="button_camera_animate">Animate</string>
- <string name="button_make_snapshot">Snapshot</string>
<string name="button_user_dot_default">Default</string>
<string name="button_user_dot_tint">Tint dot</string>
<string name="button_user_accuracy_ring_tint">Tint ring</string>
<string name="button_user_transparent_tint">tran</string>
<string name="button_open_dialog">Open dialog</string>
-
- <string name="label_fps">FPS:</string>
-
- <string name="styleMapboxStreets">Mapbox Streets</string>
- <string name="styleEmerald">Emerald</string>
- <string name="styleLight">Light</string>
- <string name="styleDark">Dark</string>
- <string name="styleSatellite">Satellite</string>
- <string name="styleSatelliteStreets">Satellite Streets</string>
-
- <string-array name="outdoors_class_list">
- <item>Day</item>
- <item>Night</item>
- </string-array>
-
- <string-array name="bulk_marker_list">
- <item>10</item>
- <item>100</item>
- <item>500</item>
- <item>1000</item>
- <item>10000</item>
- </string-array>
-
- <string-array name="user_tracking_mode">
- <item>Disabled</item>
- <item>Follow tracking</item>
- </string-array>
-
- <string-array name="user_bearing_mode">
- <item>Disabled</item>
- <item>GPS bearing</item>
- <item>Compass bearing</item>
- <!--<item>Combined mode</item>-->
- </string-array>
-
- <string name="zoom_botton">Zoom</string>
-
- <string name="scrollby_x_value">X: %1$d</string>
- <string name="scrollby_y_value">Y: %1$d</string>
<string name="button_download_region">Download region</string>
<string name="button_list_regions">List regions</string>
+ <!--Other-->
+ <string name="navigation_drawer_open">Open navigation drawer</string>
+ <string name="navigation_drawer_close">Close navigation drawer</string>
+ <string name="scrollby_x_value">X: %1$d</string>
+ <string name="scrollby_y_value">Y: %1$d</string>
<string name="dialog_camera_position">Animate to new position</string>
-
- <string name="geocoder_instructions">Tap Map To Geocode Where Black Marker Is Currently Located</string>
-
<string name="dynamic_marker_chelsea_title">Chelsea</string>
<string name="dynamic_marker_chelsea_snippet">Stamford Bridge</string>
<string name="dynamic_marker_arsenal_title">Arsenal</string>
<string name="dynamic_marker_arsenal_snippet">Emirates Stadium</string>
-
- <string name="navigation_select_location_button_text">Select Location!</string>
-
- <string name="title_section1">Different style</string>
- <string name="title_section2">Show Snackbar</string>
-
- <string name="navigation_drawer_open">Open navigation drawer</string>
- <string name="navigation_drawer_close">Close navigation drawer</string>
-
- <string name="action_example">Example action</string>
-
- <string name="action_settings">Settings</string>
- <string name="menuitem_title_rotate_gesture_enabled">Enable rotate gestures</string>
- <string name="menuitem_title_scroll_gesture_enabled">Enable scroll gestures</string>
-
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
index e358fcd5a0..777d8a5f56 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/styles.xml
@@ -1,14 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
+ <style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/primary</item>
- <item name="colorPrimaryDark">@color/primary_dark</item>
+ <item name="colorPrimaryDark">@color/primaryDark</item>
<item name="colorAccent">@color/accent</item>
<item name="android:windowBackground">@color/white</item>
+ <item name="android:spinnerItemStyle">@style/MySpinnerStyle</item>
+ <item name="android:spinnerDropDownItemStyle">@style/SpinnerItem.DropDownItem</item>
</style>
- <style name="AppTheme.ActionBar.Transparent" parent="AppTheme">
+ <style name="NoActionBar" parent="Theme.AppCompat.NoActionBar">
+ <item name="colorPrimary">@color/primary</item>
+ <item name="colorPrimaryDark">@color/primaryDark</item>
+ <item name="colorAccent">@color/accent</item>
+ <item name="android:windowBackground">@color/white</item>
+ </style>
+
+ <style name="AppTheme.ActionBar.Transparent" parent="NoActionBar">
<item name="android:windowContentOverlay">@null</item>
<item name="windowActionBarOverlay">true</item>
<item name="colorPrimary">@android:color/transparent</item>
@@ -18,6 +27,15 @@
<item name="windowActionBarOverlay">false</item>
</style>
+ <style name="MySpinnerStyle">
+ <item name="android:popupBackground">@android:color/background_light</item>
+ <item name="android:textColor">@android:color/background_light</item>
+ </style>
+
+ <style name="SpinnerItem.DropDownItem" parent="@android:style/Widget.DropDownItem.Spinner">
+ <item name="android:textColor">@android:color/background_light</item>
+ </style>
+
<style name="AppTheme" parent="AppBaseTheme" />
</resources>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
index 611e4f978c..605e159b84 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
@@ -88,4 +88,4 @@ public class AnnotationTest {
assertSame("hashcode should match", annotation.hashCode(), id);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
index 3c52c16422..ebd30f5422 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
@@ -17,9 +17,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
public class MarkerViewTest {
@@ -144,70 +141,6 @@ public class MarkerViewTest {
}
@Test
- public void testRotationUpdatePositive() {
- float startRotation = 45;
- float endRotation = 180;
-
- // allow calls to our mock
- when(mapboxMap.getMarkerViewManager()).thenReturn(markerViewManager);
-
- MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).rotation(startRotation);
- MarkerView marker = markerOptions.getMarker();
- marker.setMapboxMap(mapboxMap);
-
- marker.setRotation(endRotation);
- verify(markerViewManager, times(1)).animateRotationBy(marker, endRotation);
- }
-
- @Test
- public void testRotationUpdateNegative() {
- float startRotation = 10;
- float endRotation = 270;
-
- // allow calls to our mock
- when(mapboxMap.getMarkerViewManager()).thenReturn(markerViewManager);
-
- MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).rotation(startRotation);
- MarkerView marker = markerOptions.getMarker();
- marker.setMapboxMap(mapboxMap);
-
- marker.setRotation(endRotation);
- verify(markerViewManager, times(1)).animateRotationBy(marker, endRotation);
- }
-
- @Test
- public void testRotationUpdateMax() {
- float startRotation = 359;
- float endRotation = 0;
-
- // allow calls to our mock
- when(mapboxMap.getMarkerViewManager()).thenReturn(markerViewManager);
-
- MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).rotation(startRotation);
- MarkerView marker = markerOptions.getMarker();
- marker.setMapboxMap(mapboxMap);
-
- marker.setRotation(endRotation);
- verify(markerViewManager, times(1)).animateRotationBy(marker, 0);
- }
-
- @Test
- public void testRotationUpdateMin() {
- float startRotation = 0;
- float endRotation = 359;
-
- // allow calls to our mock
- when(mapboxMap.getMarkerViewManager()).thenReturn(markerViewManager);
-
- MarkerViewOptions markerOptions = new MarkerViewOptions().position(new LatLng()).rotation(startRotation);
- MarkerView marker = markerOptions.getMarker();
- marker.setMapboxMap(mapboxMap);
-
- marker.setRotation(endRotation);
- verify(markerViewManager, times(1)).animateRotationBy(marker, endRotation);
- }
-
- @Test
public void testVisible() {
boolean visible = false;
MarkerViewOptions markerOptions = new MarkerViewOptions().visible(visible).position(new LatLng());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index a8aad8d639..b3eace7856 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
@@ -123,4 +123,4 @@ public class CameraPositionTest {
Parcelable parcelable = MockParcel.obtain(object);
assertEquals("Parcel should match original object", parcelable, object);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java
deleted file mode 100644
index 5623afeb58..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/constants/StyleVersionTest.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.mapbox.mapboxsdk.constants;
-
-
-import com.mapbox.mapboxsdk.testapp.model.constants.AppConstant;
-
-import org.junit.Test;
-
-import static junit.framework.Assert.assertEquals;
-
-public class StyleVersionTest {
-
- private static final double DELTA = 1e-15;
-
- @Test
- public void testSanity() {
- assertEquals("Style version should match, when upgrading, verify that integers.xml is updated",
- AppConstant.STYLE_VERSION,
- 9,
- DELTA);
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index a42ca96cf5..60573f4b74 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -202,4 +202,4 @@ public class LatLngBoundsTest {
Parcelable parcel = MockParcel.obtain(latLngBounds);
assertEquals("Parcel should match original object", parcel, latLngBounds);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
index 5cbf1fa63c..06fe1c91b9 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
@@ -10,7 +10,6 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -181,17 +180,13 @@ public class LatLngTest {
@Test
public void testWrapped() {
- LatLng latLng = new LatLng(45.0, -185.0);
- LatLng wrapped = latLng.wrap();
- assertNotSame(latLng, wrapped);
- assertEquals("longitude wrapped value", wrapped.getLongitude(), 175.0, DELTA);
+ LatLng latLng = new LatLng(45.0, -185.0).wrap();
+ assertEquals("longitude wrapped value", latLng.getLongitude(), 175.0, DELTA);
}
@Test
public void testUnnecessaryWrapped() {
- LatLng latLng = new LatLng(45.0, 50.0);
- LatLng wrapped = latLng.wrap();
- assertNotSame(latLng, wrapped);
- assertEquals("longitude wrapped value", wrapped.getLongitude(), 50.0, DELTA);
+ LatLng latLng = new LatLng(45.0, 50.0).wrap();
+ assertEquals("longitude wrapped value", latLng.getLongitude(), 50.0, DELTA);
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
index 150f638e1c..de5f364a5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.maps;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.PointF;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
@@ -16,7 +17,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class TrackingSettingsTest {
@@ -30,11 +33,14 @@ public class TrackingSettingsTest {
@InjectMocks
FocalPointChangeListener focalPointChangeListener = mock(FocalPointChangeListener.class);
+ @InjectMocks
+ TrackingSettings.CameraZoomInvalidator zoomInvalidator = mock(TrackingSettings.CameraZoomInvalidator.class);
+
private TrackingSettings trackingSettings;
@Before
public void beforeTest() {
- trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointChangeListener);
+ trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointChangeListener, zoomInvalidator);
}
@Test
@@ -67,4 +73,27 @@ public class TrackingSettingsTest {
trackingSettings.setMyLocationEnabled(true);
assertTrue("Location should be enabled", trackingSettings.isMyLocationEnabled());
}
+
+ @Test
+ public void testCameraZoomTo2forTracking() {
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ verify(zoomInvalidator, atLeast(1)).zoomTo(2.0);
+ }
+
+ @Test
+ public void testFocalPointChangeForTracking() {
+ final float centerX = 32.3f;
+ final float centerY = 46.3f;
+ final PointF pointF = new PointF(centerX, centerY);
+ when(myLocationView.getCenter()).thenReturn(pointF);
+
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_FOLLOW);
+ verify(focalPointChangeListener, atLeast(1)).onFocalPointChanged(pointF);
+ }
+
+ @Test
+ public void testFocalPointChangeForNonTracking() {
+ trackingSettings.setMyLocationTrackingMode(MyLocationTracking.TRACKING_NONE);
+ verify(focalPointChangeListener, atLeast(1)).onFocalPointChanged(null);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
index 1f532255d7..fbe00b4dce 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
@@ -286,6 +286,41 @@ public class UiSettingsTest {
}
@Test
+ public void testDoubleTapGesturesEnabled() {
+ uiSettings.setDoubleTapGesturesEnabled(true);
+ assertEquals("DoubleTap gesture should be enabled", true, uiSettings.isDoubleTapGesturesEnabled());
+ }
+
+ @Test
+ public void testDoubleTapGesturesDisabled() {
+ uiSettings.setDoubleTapGesturesEnabled(false);
+ assertEquals("DoubleTap gesture should be disabled", false, uiSettings.isDoubleTapGesturesEnabled());
+ }
+
+ @Test
+ public void testDoubleTapGestureChange() {
+ assertEquals("Default state should be true", true, uiSettings.isDoubleTapGestureChangeAllowed());
+ uiSettings.setDoubleTapGestureChangeAllowed(false);
+ assertEquals("State should have been changed", false, uiSettings.isDoubleTapGestureChangeAllowed());
+ }
+
+ @Test
+ public void testDoubleTapGestureChangeAllowed() {
+ uiSettings.setDoubleTapGesturesEnabled(false);
+ assertEquals("DoubleTap gesture should be false", false, uiSettings.isDoubleTapGesturesEnabled());
+ uiSettings.setDoubleTapGesturesEnabled(true);
+ assertEquals("DoubleTap gesture should be true", true, uiSettings.isDoubleTapGesturesEnabled());
+ }
+
+ @Test
+ public void testDoubleTapGestureChangeDisallowed() {
+ assertEquals("DoubleTap gesture should be true", true, uiSettings.isDoubleTapGesturesEnabled());
+ uiSettings.setDoubleTapGestureChangeAllowed(false);
+ uiSettings.setDoubleTapGesturesEnabled(false);
+ assertEquals("DoubleTap gesture change should be ignored", true, uiSettings.isDoubleTapGesturesEnabled());
+ }
+
+ @Test
public void testScrollGesturesEnabled() {
uiSettings.setScrollGesturesEnabled(true);
assertEquals("Scroll gesture should be enabled", true, uiSettings.isScrollGesturesEnabled());
@@ -337,4 +372,4 @@ public class UiSettingsTest {
assertEquals("Zoom gesture should be disabled", false, uiSettings.isZoomGesturesEnabled());
assertEquals("Scroll gesture should be disabled", false, uiSettings.isScrollGesturesEnabled());
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
index 4e82ca2318..bac1154d62 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
@@ -1,9 +1,12 @@
package com.mapbox.mapboxsdk.style.layers;
+import com.mapbox.mapboxsdk.style.functions.Function;
+
import org.junit.Test;
-import static com.mapbox.mapboxsdk.style.layers.Function.stop;
-import static com.mapbox.mapboxsdk.style.layers.Function.zoom;
+import static com.mapbox.mapboxsdk.style.functions.Function.zoom;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stop.stop;
+import static com.mapbox.mapboxsdk.style.functions.stops.Stops.interval;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineBlur;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
@@ -15,9 +18,10 @@ public class FunctionTest {
@Test
public void testZoomFunction() {
- Function zoomF = zoom(
+ Function<Float, Float> zoomF = zoom(interval(
stop(1f, lineBlur(1f)),
stop(10f, lineBlur(20f))
+ )
);
assertNotNull(zoomF.toValueObject());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/ExponentialBackOffTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/ExponentialBackOffTest.java
deleted file mode 100644
index 50ce19c050..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/ExponentialBackOffTest.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.mapbox.mapboxsdk.telemetry;
-
-import org.junit.Test;
-
-import static junit.framework.Assert.assertEquals;
-
-public class ExponentialBackOffTest {
-
- @Test
- public void testExponentialBackOff() {
- MapboxEventManager.ExponentialBackoffCounter counter = new MapboxEventManager.ExponentialBackoffCounter();
- assertEquals(30000, counter.getNextCount());
- assertEquals(60000, counter.getNextCount());
- assertEquals(90000, counter.getNextCount());
- assertEquals(120000, counter.getNextCount());
- assertEquals(150000, counter.getNextCount());
- assertEquals(180000, counter.getNextCount());
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
index 1f0e8cb72b..e08d5a9a03 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/build.gradle
@@ -1,20 +1,15 @@
apply plugin: 'com.android.application'
-ext {
- wearableVersion = '2.0.0-alpha3'
- leakCanaryVersion = '1.5'
-}
-
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdkVersion rootProject.ext.compileSdkVersion
+ buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.mapbox.mapboxsdk.testapp"
- minSdkVersion 21
- targetSdkVersion 25
- versionCode 11
- versionName "5.0.0"
+ minSdkVersion rootProject.ext.minSdkVersion
+ targetSdkVersion rootProject.ext.targetSdkVersion
+ versionCode rootProject.ext.versionCode
+ versionName rootProject.ext.versionName
}
buildTypes {
@@ -34,19 +29,18 @@ dependencies {
}
// Wear
- compile fileTree(dir: 'libs', include: ['*.jar'])
- compile "com.google.android.support:wearable:${wearableVersion}"
- provided "com.google.android.wearable:wearable:${wearableVersion}"
+ compile rootProject.ext.dep.wearCompile
+ provided rootProject.ext.dep.wearProvided
// Leak Canary
- debugCompile "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}"
- releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
- testCompile "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
+ debugCompile rootProject.ext.dep.leakCanaryDebug
+ releaseCompile rootProject.ext.dep.leakCanaryRelease
+ testCompile rootProject.ext.dep.leakCanaryTest
// Testing dependencies
- testCompile 'junit:junit:4.12'
- testCompile 'org.mockito:mockito-core:2.2.27'
+ testCompile rootProject.ext.dep.junit
+ testCompile rootProject.ext.dep.mockito
}
apply from: 'gradle-config.gradle'
-apply from: 'gradle-checkstyle.gradle' \ No newline at end of file
+apply from: 'gradle-checkstyle.gradle'
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle
index cdcc7f1e23..bfb8341dbc 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle
@@ -14,4 +14,4 @@ task checkstyle(type: Checkstyle) {
exclude '**/gen/**'
classpath = files()
ignoreFailures = false
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-config.gradle b/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-config.gradle
index fac47cb2a9..27c13b935b 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-config.gradle
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/gradle-config.gradle
@@ -19,4 +19,4 @@ task accessToken {
gradle.projectsEvaluated {
preBuild.dependsOn('accessToken')
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/AndroidManifest.xml
index 22c44f9721..36588a89f5 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/AndroidManifest.xml
@@ -33,15 +33,15 @@
</activity>
<activity
- android:name=".activity.SimpleMapViewActivity"
+ android:name=".activity.SimpleWearMapActivity"
android:label="@string/activity_simple_mapview_title">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
</activity>
- <service android:name="com.mapbox.mapboxsdk.telemetry.TelemetryService"/>
+ <service android:name="com.mapbox.services.android.telemetry.service.TelemetryService"/>
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/FeatureOverviewActivity.java b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/FeatureOverviewActivity.java
index 2a8bf9396f..1fe8a6cf10 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/FeatureOverviewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/FeatureOverviewActivity.java
@@ -32,7 +32,7 @@ public class FeatureOverviewActivity extends WearableActivity implements Feature
exampleItemModels = new ArrayList<>();
exampleItemModels.add(new Feature(R.string.activity_simple_mapview_title, new Intent(FeatureOverviewActivity.this,
- SimpleMapViewActivity.class)));
+ SimpleWearMapActivity.class)));
FeatureAdapter exampleAdapter = new FeatureAdapter(FeatureOverviewActivity.this, exampleItemModels);
wearableRecyclerView.setAdapter(exampleAdapter);
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleMapViewActivity.java b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleWearMapActivity.java
index b24b626fe6..f5bca0e051 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleMapViewActivity.java
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/activity/SimpleWearMapActivity.java
@@ -8,7 +8,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.weartestapp.R;
-public class SimpleMapViewActivity extends WearableActivity {
+public class SimpleWearMapActivity extends WearableActivity {
private MapView mapView;
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/adapter/FeatureAdapter.java b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/adapter/FeatureAdapter.java
index 7539a84d6e..1ef17e2d7a 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/adapter/FeatureAdapter.java
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/adapter/FeatureAdapter.java
@@ -75,4 +75,4 @@ public class FeatureAdapter extends WearableRecyclerView.Adapter<FeatureAdapter.
public interface ItemSelectedListener {
void onItemSelected(int position);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/utils/OffsettingHelper.java b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/utils/OffsettingHelper.java
index 5b5d512c45..8550d0d016 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/utils/OffsettingHelper.java
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/java/com/mapbox/weartestapp/utils/OffsettingHelper.java
@@ -34,7 +34,7 @@ public class OffsettingHelper extends DefaultOffsettingHelper {
}
@Override
- protected void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
+ public void adjustAnchorOffsetXY(View child, float[] anchorOffsetXY) {
anchorOffsetXY[0] = child.getHeight() / 2.0f;
}
}
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_feature_overview.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_feature_overview.xml
index 07cfcd3c51..d1a314cfe2 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_feature_overview.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_feature_overview.xml
@@ -14,4 +14,4 @@
android:layout_height="match_parent"
android:scrollbars="vertical" />
-</android.support.wearable.view.BoxInsetLayout> \ No newline at end of file
+</android.support.wearable.view.BoxInsetLayout>
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
index 948f92e30b..8f260c46ff 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/activity_simple_mapview.xml
@@ -6,7 +6,7 @@
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".activity.SimpleMapViewActivity"
+ tools:context=".activity.SimpleWearMapActivity"
tools:deviceIds="wear">
<com.mapbox.mapboxsdk.maps.MapView
@@ -19,4 +19,4 @@
mapbox:mapbox_cameraZoom="11"
mapbox:mapbox_uiZoomControls="false"/>
-</FrameLayout> \ No newline at end of file
+</FrameLayout>
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/item_curved_layout.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/item_curved_layout.xml
index e3a9b476a1..3d81ba3ad5 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/item_curved_layout.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/layout/item_curved_layout.xml
@@ -16,4 +16,4 @@
android:textColor="@color/mapboxWhite"
android:textSize="14sp"/>
-</LinearLayout> \ No newline at end of file
+</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/values/colors.xml b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/values/colors.xml
index 1c40e40e1a..5bcdbe93bf 100644
--- a/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/values/colors.xml
+++ b/platform/android/MapboxGLAndroidSDKWearTestApp/src/main/res/values/colors.xml
@@ -28,4 +28,4 @@
<color name="mapboxNavy">#28353D</color>
<color name="mapboxNavyDark">#222B30</color>
-</resources> \ No newline at end of file
+</resources>
diff --git a/platform/android/bitrise.yml b/platform/android/bitrise.yml
index 7fcbd524f2..aadcba79be 100644
--- a/platform/android/bitrise.yml
+++ b/platform/android/bitrise.yml
@@ -28,15 +28,6 @@ workflows:
envman add --key SKIPCI --value false
fi
- script:
- title: Configure GL-native build environement
- run_if: '{{enveq "SKIPCI" "false"}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y pkg-config nodejs cmake
- - script:
title: Run Checkstyle
run_if: '{{enveq "SKIPCI" "false"}}'
inputs:
@@ -166,14 +157,6 @@ workflows:
scheduled:
steps:
- script:
- title: Configure GL-native build environement
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y pkg-config nodejs cmake
- - script:
title: Configure AWS-CLI
inputs:
- content: |-
@@ -200,11 +183,7 @@ workflows:
#!/bin/bash
echo "Compile libmapbox-gl.so for all supportd abi's:"
export BUILDTYPE=Release
- 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 apackage
cd platform/android && ./gradlew :MapboxGLAndroidSDK:assembleRelease
- script:
title: Publish to maven
@@ -227,14 +206,6 @@ workflows:
devicefarmUpload:
steps:
- script:
- title: Configure GL-native build environement
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y pkg-config nodejs cmake
- - script:
title: Build release
inputs:
- content: |-
@@ -277,14 +248,6 @@ workflows:
nightly-release:
steps:
- script:
- title: Configure GL-native build environement
- inputs:
- - content: |-
- #!/bin/bash
- set -eu -o pipefail
- curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
- sudo apt-get install -y pkg-config nodejs cmake
- - script:
title: Configure AWS-CLI
inputs:
- content: |-
@@ -298,11 +261,7 @@ workflows:
#!/bin/bash
echo "Compile libmapbox-gl.so for all supportd abi's:"
export BUILDTYPE=Release
- 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 apackage
cd platform/android && ./gradlew :MapboxGLAndroidSDK:assembleRelease
- script:
title: Log metrics
diff --git a/platform/android/build.gradle b/platform/android/build.gradle
index 9ba9210af4..69eb6616d1 100644
--- a/platform/android/build.gradle
+++ b/platform/android/build.gradle
@@ -1,7 +1,6 @@
buildscript {
repositories {
jcenter()
- maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
@@ -13,10 +12,12 @@ buildscript {
allprojects {
repositories {
jcenter()
- maven { url "http://oss.sonatype.org/content/repositories/snapshots/" }
}
}
task wrapper(type: Wrapper) {
gradleVersion = '3.2.1'
}
+
+apply from: rootProject.file('dependencies.gradle')
+
diff --git a/platform/android/checkstyle.xml b/platform/android/checkstyle.xml
index 3449036e99..c73ada1565 100644
--- a/platform/android/checkstyle.xml
+++ b/platform/android/checkstyle.xml
@@ -20,7 +20,7 @@
<property name="lineSeparator" value="lf" />
</module> -->
<module name="FileLength">
- <property name="max" value="2042"/>
+ <property name="max" value="3000"/>
</module>
<module name="FileTabCharacter"/>
@@ -31,6 +31,11 @@
<property name="message" value="Line has trailing spaces."/>
</module>
+ <module name="RegexpMultiline">
+ <property name="format" value="^;"/>
+ <property name="message" value="Line starts with an empty statement."/>
+ </module>
+
<module name="TreeWalker">
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
@@ -216,5 +221,6 @@
<property name="exceptionVariableName" value="expected"/>
</module>
<module name="CommentsIndentation"/>
+ <module name="EmptyStatement"/>
</module>
</module>
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index c3c461ffa1..18458deba6 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -2,9 +2,6 @@ add_definitions(-DMBGL_USE_GLES2=1)
include(cmake/test-files.cmake)
-#Include to use build specific variables
-include(${CMAKE_CURRENT_BINARY_DIR}/toolchain.cmake)
-
# Build thin archives.
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> cruT <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> cruT <TARGET> <LINK_FLAGS> <OBJECTS>")
@@ -18,33 +15,21 @@ if ((ANDROID_ABI STREQUAL "armeabi") OR (ANDROID_ABI STREQUAL "armeabi-v7a") OR
set(CMAKE_SHARED_LINKER_FLAGS "-fuse-ld=gold -Wl,--icf=safe ${CMAKE_SHARED_LINKER_FLAGS}")
endif()
-mason_use(jni.hpp VERSION 2.0.0 HEADER_ONLY)
-mason_use(libjpeg-turbo VERSION 1.5.0)
-mason_use(libpng VERSION 1.6.25)
+mason_use(jni.hpp VERSION 3.0.0 HEADER_ONLY)
mason_use(libzip VERSION 1.1.3)
mason_use(nunicode VERSION 1.7.1)
mason_use(sqlite VERSION 3.14.2)
-mason_use(gtest VERSION 1.7.0)
+mason_use(gtest VERSION 1.8.0)
mason_use(icu VERSION 58.1)
set(ANDROID_SDK_PROJECT_DIR ${CMAKE_SOURCE_DIR}/platform/android/MapboxGLAndroidSDK)
-set(ANDROID_JNI_TARGET_DIR ${ANDROID_SDK_PROJECT_DIR}/src/main/jniLibs/${ANDROID_JNIDIR})
+set(ANDROID_JNI_TARGET_DIR ${ANDROID_SDK_PROJECT_DIR}/src/main/jniLibs/${ANDROID_ABI})
set(ANDROID_ASSETS_TARGET_DIR ${ANDROID_SDK_PROJECT_DIR}/src/main/assets)
-set(ANDROID_TEST_APP_JNI_TARGET_DIR ${CMAKE_SOURCE_DIR}/platform/android/MapboxGLAndroidSDKTestApp/src/main/jniLibs/${ANDROID_JNIDIR})
-
-macro(mbgl_android_copy_asset source target)
- add_custom_command(
- OUTPUT ${ANDROID_ASSETS_TARGET_DIR}/${target}
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/${source} ${ANDROID_ASSETS_TARGET_DIR}/${target}
- DEPENDS ${CMAKE_SOURCE_DIR}/${source}
- )
-endmacro()
-
-mbgl_android_copy_asset(common/ca-bundle.crt ca-bundle.crt)
+set(ANDROID_TEST_APP_JNI_TARGET_DIR ${CMAKE_SOURCE_DIR}/platform/android/MapboxGLAndroidSDKTestApp/src/main/jniLibs/${ANDROID_ABI})
-add_custom_target(mbgl-copy-android-assets
- DEPENDS ${ANDROID_ASSETS_TARGET_DIR}/ca-bundle.crt
-)
+if (NOT DEFINED ANDROID_TOOLCHAIN_PREFIX)
+ set(ANDROID_TOOLCHAIN_PREFIX "${MASON_XC_ROOT}/bin/${ANDROID_TOOLCHAIN}-")
+endif()
## mbgl core ##
@@ -82,11 +67,16 @@ macro(mbgl_platform_core)
PRIVATE platform/default/utf.cpp
# Image handling
- PRIVATE platform/default/image.cpp
- PRIVATE platform/default/png_reader.cpp
- PRIVATE platform/default/jpeg_reader.cpp
+ PRIVATE platform/default/png_writer.cpp
+ PRIVATE platform/android/src/bitmap.cpp
+ PRIVATE platform/android/src/bitmap.hpp
+ PRIVATE platform/android/src/bitmap_factory.cpp
+ PRIVATE platform/android/src/bitmap_factory.hpp
+ PRIVATE platform/android/src/image.cpp
# Thread pool
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
PRIVATE platform/default/mbgl/util/default_thread_pool.hpp
@@ -124,6 +114,8 @@ macro(mbgl_platform_core)
platform/android/src/style/layers/raster_layer.hpp
platform/android/src/style/layers/symbol_layer.cpp
platform/android/src/style/layers/symbol_layer.hpp
+ platform/android/src/style/layers/unknown_layer.cpp
+ platform/android/src/style/layers/unknown_layer.hpp
platform/android/src/style/sources/geojson_source.cpp
platform/android/src/style/sources/geojson_source.hpp
platform/android/src/style/sources/source.cpp
@@ -132,8 +124,24 @@ macro(mbgl_platform_core)
platform/android/src/style/sources/sources.hpp
platform/android/src/style/sources/raster_source.cpp
platform/android/src/style/sources/raster_source.hpp
+ platform/android/src/style/sources/unknown_source.cpp
+ platform/android/src/style/sources/unknown_source.hpp
platform/android/src/style/sources/vector_source.cpp
platform/android/src/style/sources/vector_source.hpp
+ platform/android/src/style/functions/stop.cpp
+ platform/android/src/style/functions/stop.hpp
+ platform/android/src/style/functions/categorical_stops.cpp
+ platform/android/src/style/functions/categorical_stops.hpp
+ platform/android/src/style/functions/exponential_stops.cpp
+ platform/android/src/style/functions/exponential_stops.hpp
+ platform/android/src/style/functions/identity_stops.cpp
+ platform/android/src/style/functions/identity_stops.hpp
+ platform/android/src/style/functions/interval_stops.cpp
+ platform/android/src/style/functions/interval_stops.hpp
+
+ # FileSource holder
+ platform/android/src/file_source.cpp
+ platform/android/src/file_source.hpp
# Connectivity
platform/android/src/connectivity_listener.cpp
@@ -143,6 +151,46 @@ macro(mbgl_platform_core)
platform/android/src/native_map_view.cpp
platform/android/src/native_map_view.hpp
+ # Java core classes
+ platform/android/src/java/util.cpp
+ platform/android/src/java/util.hpp
+
+ # Graphics
+ platform/android/src/graphics/pointf.cpp
+ platform/android/src/graphics/pointf.hpp
+ platform/android/src/graphics/rectf.cpp
+ platform/android/src/graphics/rectf.hpp
+
+ # Geometry
+ platform/android/src/geometry/feature.cpp
+ platform/android/src/geometry/feature.hpp
+ platform/android/src/geometry/lat_lng.cpp
+ platform/android/src/geometry/lat_lng.hpp
+ platform/android/src/geometry/lat_lng_bounds.cpp
+ platform/android/src/geometry/lat_lng_bounds.hpp
+ platform/android/src/geometry/projected_meters.cpp
+ platform/android/src/geometry/projected_meters.hpp
+
+ # Annotation
+ platform/android/src/annotation/marker.cpp
+ platform/android/src/annotation/marker.hpp
+ platform/android/src/annotation/polygon.cpp
+ platform/android/src/annotation/polygon.hpp
+ platform/android/src/annotation/polyline.cpp
+ platform/android/src/annotation/polyline.hpp
+
+ # Offline
+ platform/android/src/offline/offline_manager.cpp
+ platform/android/src/offline/offline_manager.hpp
+ platform/android/src/offline/offline_region.cpp
+ platform/android/src/offline/offline_region.hpp
+ platform/android/src/offline/offline_region_definition.cpp
+ platform/android/src/offline/offline_region_definition.hpp
+ platform/android/src/offline/offline_region_error.cpp
+ platform/android/src/offline/offline_region_error.hpp
+ platform/android/src/offline/offline_region_status.cpp
+ platform/android/src/offline/offline_region_status.hpp
+
# Main jni bindings
platform/android/src/attach_env.cpp
platform/android/src/attach_env.hpp
@@ -160,8 +208,6 @@ macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC sqlite)
target_add_mason_package(mbgl-core PUBLIC nunicode)
- target_add_mason_package(mbgl-core PUBLIC libpng)
- target_add_mason_package(mbgl-core PUBLIC libjpeg-turbo)
target_add_mason_package(mbgl-core PUBLIC libzip)
target_add_mason_package(mbgl-core PUBLIC geojson)
target_add_mason_package(mbgl-core PUBLIC jni.hpp)
@@ -178,6 +224,7 @@ macro(mbgl_platform_core)
target_link_libraries(mbgl-core
PUBLIC -llog
PUBLIC -landroid
+ PUBLIC -ljnigraphics
PUBLIC -lEGL
PUBLIC -lGLESv2
PUBLIC -lstdc++
@@ -193,10 +240,6 @@ add_library(mapbox-gl SHARED
platform/android/src/main.cpp
)
-add_dependencies(mapbox-gl
- mbgl-copy-android-assets
-)
-
target_compile_options(mapbox-gl
PRIVATE -fvisibility=hidden
PRIVATE -ffunction-sections
@@ -212,7 +255,7 @@ target_link_libraries(mapbox-gl
# Create a stripped version of the library and copy it to the JNIDIR.
add_custom_command(TARGET mapbox-gl POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_JNI_TARGET_DIR}
- COMMAND ${STRIP_COMMAND} $<TARGET_FILE:mapbox-gl> -o ${ANDROID_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:mapbox-gl>)
+ COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mapbox-gl> -o ${ANDROID_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:mapbox-gl>)
## Test library ##
@@ -255,7 +298,6 @@ target_include_directories(mbgl-test
PRIVATE test/include
PRIVATE test/src
PRIVATE platform/default
- PRIVATE ${MBGL_GENERATED}/include
)
target_link_libraries(mbgl-test
@@ -274,8 +316,8 @@ target_add_mason_package(mbgl-test PRIVATE geojsonvt)
add_custom_command(TARGET mbgl-test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/stripped
- COMMAND ${STRIP_COMMAND} $<TARGET_FILE:mapbox-gl> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mapbox-gl>
- COMMAND ${STRIP_COMMAND} $<TARGET_FILE:mbgl-test> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mbgl-test>)
+ COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mapbox-gl> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mapbox-gl>
+ COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:mbgl-test> -o ${CMAKE_CURRENT_BINARY_DIR}/stripped/$<TARGET_FILE_NAME:mbgl-test>)
## Custom layer example ##
@@ -297,4 +339,4 @@ target_link_libraries(example-custom-layer
add_custom_command(TARGET example-custom-layer POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${ANDROID_TEST_APP_JNI_TARGET_DIR}
- COMMAND ${STRIP_COMMAND} $<TARGET_FILE:example-custom-layer> -o ${ANDROID_TEST_APP_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:example-custom-layer>)
+ COMMAND ${ANDROID_TOOLCHAIN_PREFIX}strip $<TARGET_FILE:example-custom-layer> -o ${ANDROID_TEST_APP_JNI_TARGET_DIR}/$<TARGET_FILE_NAME:example-custom-layer>)
diff --git a/platform/android/dependencies.gradle b/platform/android/dependencies.gradle
new file mode 100644
index 0000000000..2cdb455190
--- /dev/null
+++ b/platform/android/dependencies.gradle
@@ -0,0 +1,55 @@
+ext {
+ minSdkVersion = 15
+ targetSdkVersion = 25
+ compileSdkVersion = 25
+ buildToolsVersion = "25.0.2"
+
+ versionCode = 11
+ versionName = "5.0.0"
+
+ supportLibVersion = "25.1.1"
+ leakCanaryVersion = '1.5'
+ wearableVersion = '2.0.0'
+
+ espressoVersion = '2.2.2'
+ testRunnerVersion = '0.5'
+
+ dep = [
+ // mapbox
+ mapboxJavaServices : 'com.mapbox.mapboxsdk:mapbox-java-services:2.0.0-beta.2@jar',
+ mapboxJavaGeoJSON : 'com.mapbox.mapboxsdk:mapbox-java-geojson:2.0.0-beta.2@jar',
+ mapboxAndroidTelemetry : 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.0.0-beta.2@aar',
+
+ // mapzen lost
+ lost : 'com.mapzen.android:lost:2.1.2',
+
+ // unit test
+ junit : 'junit:junit:4.12',
+ mockito : 'org.mockito:mockito-core:2.2.27',
+
+ // instrumentation test
+ testSpoonRunner : 'com.squareup.spoon:spoon-client:1.6.2',
+ testRunner : "com.android.support.test:runner:${testRunnerVersion}",
+ testRules : "com.android.support.test:rules:${testRunnerVersion}",
+ testEspressoCore : "com.android.support.test.espresso:espresso-core:${espressoVersion}",
+ testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${espressoVersion}",
+
+ // support
+ supportAnnotations : "com.android.support:support-annotations:${supportLibVersion}",
+ supportAppcompatV7 : "com.android.support:appcompat-v7:${supportLibVersion}",
+ supportV4 : "com.android.support:support-v4:${supportLibVersion}",
+ supportDesign : "com.android.support:design:${supportLibVersion}",
+ supportRecyclerView : "com.android.support:recyclerview-v7:${supportLibVersion}",
+
+ // wear
+ wearCompile : "com.google.android.support:wearable:${wearableVersion}",
+ wearProvided : "com.google.android.wearable:wearable:${wearableVersion}",
+
+ // square crew
+ timber : 'com.jakewharton.timber:timber:4.5.1',
+ okhttp3 : 'com.squareup.okhttp3:okhttp:3.6.0',
+ leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${leakCanaryVersion}",
+ leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}",
+ leakCanaryTest : "com.squareup.leakcanary:leakcanary-android-no-op:${leakCanaryVersion}"
+ ]
+} \ No newline at end of file
diff --git a/platform/android/scripts/debug.sh b/platform/android/scripts/debug.sh
index efed96969a..c3390b4ce1 100755
--- a/platform/android/scripts/debug.sh
+++ b/platform/android/scripts/debug.sh
@@ -5,13 +5,12 @@ set -o pipefail
# Automation of https://github.com/mapbox/mapbox-gl-native/wiki/Android-debugging-with-remote-GDB
-export MASON_DIR="`pwd`/.mason"
-export PATH="${MASON_DIR}:${PATH}"
-
-export MASON_ANDROID_ABI=x86
export MASON_ANDROID_ARCH=x86
export MASON_ANDROID_PLATFORM=9
-export MASON_NDK_PACKAGE_VERSION=${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-r12b
+export MASON_ANDROID_NDK_VERSION=r13b
+
+export MASON_XC_ROOT=`scripts/mason.sh PREFIX android-ndk VERSION ${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}-${MASON_ANDROID_NDK_VERSION}`
+source ${MASON_XC_ROOT}/toolchain.sh
if [[ $1 == '--prepare' ]]; then
mkdir -p ~/.android/debugging/{vendor,system}_lib
@@ -21,16 +20,16 @@ if [[ $1 == '--prepare' ]]; then
adb pull /system/bin/app_process32 ~/.android/debugging
adb pull /system/bin/linker ~/.android/debugging
- if [[ ${MASON_ANDROID_ABI} == 'x86_64' || ${MASON_ANDROID_ABI} == 'mips64' ]]; then
+ if [[ ${MASON_ANDROID_ARCH} == 'arm-v8' || ${MASON_ANDROID_ARCH} == 'x86-64' || ${MASON_ANDROID_ARCH} == 'mips-64' ]]; then
adb pull /system/bin/app_process64 ~/.android/debugging
adb pull /system/bin/linker64 ~/.android/debugging
fi
- cp `mason prefix android-ndk ${MASON_NDK_PACKAGE_VERSION}`/prebuilt/android-${MASON_ANDROID_ABI}/gdbserver/gdbserver \
- platform/android/MapboxGLAndroidSDK/src/main/jniLibs/${MASON_ANDROID_ABI}/gdbserver.so
+ cp ${MASON_XC_ROOT}/prebuilt/gdbserver/gdbserver \
+ platform/android/MapboxGLAndroidSDK/src/main/jniLibs/${ANDROID_ABI}/gdbserver.so
fi
-adb install -rtdg platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk
+adb install -r -t -d -g platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk
adb shell am start -n "com.mapbox.mapboxsdk.testapp/com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity" \
-a android.intent.action.MAIN -c android.intent.category.LAUNCHER
@@ -38,9 +37,6 @@ adb forward tcp:5039 tcp:5039
adb shell run-as com.mapbox.mapboxsdk.testapp '/data/data/com.mapbox.mapboxsdk.testapp/lib/gdbserver.so \
--attach :5039 `pgrep com.mapbox.mapboxsdk.testapp`' &
-export MASON_PLATFORM=android
-export PATH=`mason env PATH`
-`mason env MASON_ANDROID_TOOLCHAIN`-gdb \
+${MASON_XC_ROOT}/bin/gdb \
-ex "target remote :5039" \
- -ex "set solib-search-path ~/.android/debugging:~/.android/debugging/system_lib:~/.android/debugging/vendor_lib:~/.android/debugging/vendor_lib/egl:./build/android-${MASON_ANDROID_ABI}/Debug/lib.target/"
-
+ -ex "set solib-search-path ~/.android/debugging:~/.android/debugging/system_lib:~/.android/debugging/vendor_lib:~/.android/debugging/vendor_lib/egl:./build/android-${MASON_ANDROID_ARCH}-${MASON_ANDROID_PLATFORM}/Debug/lib.target/"
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index bcfd6bc0df..09563f3b9d 100644
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -2,15 +2,15 @@
const fs = require('fs');
const ejs = require('ejs');
-const spec = require('mapbox-gl-style-spec').latest;
+const spec = require('../../../mapbox-gl-js/src/style-spec/reference/v8');
const _ = require('lodash');
require('../../../scripts/style-code');
// Specification parsing //
-//Collect layer types from spec
-const layers = Object.keys(spec.layer.type.values).map((type) => {
+// Collect layer types from spec
+var layers = Object.keys(spec.layer.type.values).map((type) => {
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
if (name !== 'visibility') {
spec[`layout_${type}`][name].name = name;
@@ -34,7 +34,10 @@ const layers = Object.keys(spec.layer.type.values).map((type) => {
};
});
-//Process all layer properties
+// XXX Remove fill-extrusion layer for now
+layers = _(layers).filter(layer => layer.type != "fill-extrusion").value();
+
+// Process all layer properties
const layoutProperties = _(layers).map('layoutProperties').flatten().value();
const paintProperties = _(layers).map('paintProperties').flatten().value();
const allProperties = _(layoutProperties).union(paintProperties).value();
@@ -155,18 +158,21 @@ global.defaultValueJava = function(property) {
* Produces documentation for property factory methods
*/
global.propertyFactoryMethodDoc = function (property) {
- let doc = property.doc;
- //Match other items in back ticks
+ var replaceIfPixels = function (doc) {
+ return doc.replace('pixels', 'density-independent pixels')
+ }
+ let doc = replaceIfPixels(property.doc);
+ // Match other items in back ticks
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
if (str.substr(offset - 4, 3) !== 'CSS' && symbol[0].toUpperCase() != symbol[0] && _(enumProperties).filter({'name': symbol}).value().length > 0) {
- //Property 'enums'
+ // Property 'enums'
symbol = snakeCaseUpper(symbol);
return '{@link Property.' + symbol + '}';
} else if( _(allProperties).filter({'name': symbol}).value().length > 0) {
- //Other properties
+ // Other properties
return '{@link PropertyFactory#' + camelizeWithLeadingLowercase(symbol) + '}';
} else {
- //Left overs
+ // Left overs
return '`' + symbol + '`';
}
});
@@ -193,25 +199,33 @@ global.propertyValueDoc = function (property, value) {
return 'is equivalent to {@link Property#' + propertyValue + '}';
});
- //Match other items in back ticks
+ // Match other items in back ticks
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) {
- //Property values
+ // Property values
propertyValue = snakeCaseUpper(property.name) + '_' + snakeCaseUpper(symbol);
console.log("Transforming", symbol, propertyValue);
return '{@link Property#' + `${propertyValue}` + '}';
} else if (str.substr(offset - 4, 3) !== 'CSS' && symbol[0].toUpperCase() != symbol[0]) {
- //Property 'enums'
+ // Property 'enums'
symbol = snakeCaseUpper(symbol);
return '{@link ' + symbol + '}';
} else {
- //Left overs
+ // Left overs
return symbol
}
});
return doc;
};
+global.supportsZoomFunction = function (property) {
+ return property['zoom-function'] === true;
+};
+
+global.supportsPropertyFunction = function (property) {
+ return property['property-function'] === true;
+};
+
// Template processing //
// Java + JNI Layers (Peer model)
@@ -242,7 +256,7 @@ writeIfModified(
enumPropertyJavaTemplate({properties: enumProperties})
);
-//De-duplicate enum properties before processing jni property templates
+// De-duplicate enum properties before processing jni property templates
const enumPropertiesDeDup = _(enumProperties).uniqBy(global.propertyNativeType).value();
// JNI Enum property conversion templates
diff --git a/platform/android/scripts/ndk.sh b/platform/android/scripts/ndk.sh
new file mode 100755
index 0000000000..96a314a3c2
--- /dev/null
+++ b/platform/android/scripts/ndk.sh
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+set -u
+
+# This script produces an env.sh file, which contains the paths to CMake, and the flags required to
+# create a build. It first tries to use the Android NDK, but falls back to installing it via Mason.
+
+function error { >&2 echo -e "\033[1m\033[31m$@\033[0m"; }
+function warning { >&2 echo -e "\033[1m\033[33m$@\033[0m"; }
+function status { >&2 echo -e "\033[1m\033[36m$@\033[0m"; }
+function info { >&2 echo -e "\033[1m\033[32m$@\033[0m"; }
+
+if [ "$#" -ne 3 ]; then
+ error "Usage: $0 <short arch> <long arch> <api level>"
+fi
+
+NDK_ANDROID_VERSION=$1-$3
+ANDROID_NATIVE_API_LEVEL=$3
+ANDROID_ABI=$2
+
+function mason_ndk {
+ local CMAKE=${CMAKE:-cmake}
+ MASON_XC_ROOT="`${CMAKE} -P cmake/mason.cmake PREFIX android-ndk VERSION ${NDK_ANDROID_VERSION}-r13b`"
+
+ local TOOLCHAIN="${MASON_XC_ROOT}/toolchain.cmake"
+ if [ ! -f "${TOOLCHAIN}" ]; then
+ error "Can't find CMake toolchain file at ${TOOLCHAIN}."
+ exit 1
+ fi
+
+ info "Using Mason-provided Android NDK at ${MASON_XC_ROOT}"
+ echo CMAKE=\"${CMAKE}\"
+ echo CMAKE_GENERATOR=\"Ninja\"
+ echo CMAKE_ARGS=\" \
+ -DCMAKE_MAKE_PROGRAM=`pwd`/${NINJA} \
+ -DMASON_XC_ROOT=${MASON_XC_ROOT} \
+ -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
+ \"
+}
+
+function system_ndk {
+ if [[ ${USE_MASON_NDK:-} ]]; then
+ return 1
+ fi
+
+ if [ -f platform/android/local.properties ]; then
+ local SDK_DIR=$(sed -n -e 's/^sdk.dir=\(.*\)$/\1/p' platform/android/local.properties)
+ fi
+
+ if [ ! -d "${SDK_DIR:-}" ]; then
+ if [ ! -z "${ANDROID_HOME:-}" ]; then
+ local SDK_DIR="${ANDROID_HOME}"
+ else
+ error "Can't find the Android SDK. Set \$ANDROID_HOME to the SDK path."
+ exit 1
+ fi
+ fi
+
+ local NDK_DIR="${ANDROID_NDK_HOME:-${SDK_DIR}/ndk-bundle}"
+ if [ ! -d "${NDK_DIR}" ]; then
+ warning "Can't find the Android NDK. If it is installed, set \$ANDROID_NDK_HOME to the NDK path."
+ return 1
+ fi
+
+ # Try to install CMake if it's not installed yet.
+ mkdir -p "${SDK_DIR}/cmake"
+ local CMAKE_VERSION=/$(ls "${SDK_DIR}/cmake" | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -n 1)
+ local CMAKE="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/cmake"
+ if [ ! -f "${CMAKE}" ]; then
+ status "Trying to install CMake..."
+ mkdir -p "${SDK_DIR}/licenses"
+ echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "${SDK_DIR}/licenses/android-sdk-license"
+ "${SDK_DIR}/tools/bin/sdkmanager" --list | grep cmake | tail -n 1 | cut -d \| -f 1 | xargs "${SDK_DIR}/tools/bin/sdkmanager" >&2
+ CMAKE_VERSION=/$(ls "${SDK_DIR}/cmake" | sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n | tail -n 1)
+ CMAKE="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/cmake"
+ if [ ! -f "${CMAKE}" ]; then
+ error "Can't find CMake at ${CMAKE}."
+ return 1
+ fi
+ fi
+
+ local NINJA="${SDK_DIR}/cmake${CMAKE_VERSION:-}/bin/ninja"
+ if [ ! -f "${NINJA}" ]; then
+ error "Can't find Ninja at ${NINJA}."
+ return 1
+ fi
+
+ local TOOLCHAIN="${NDK_DIR}/build/cmake/android.toolchain.cmake"
+ if [ ! -f "${TOOLCHAIN}" ]; then
+ error "Can't find CMake toolchain file at ${TOOLCHAIN}."
+ return 1
+ fi
+
+ info "Using system-provided Android NDK at ${NDK_DIR}"
+ echo CMAKE=\"${CMAKE}\"
+ echo CMAKE_GENERATOR=\"Android Gradle - Ninja\"
+ echo CMAKE_ARGS=\" \
+ -DANDROID_ABI=${ANDROID_ABI} \
+ -DANDROID_NDK=${NDK_DIR} \
+ -DCMAKE_MAKE_PROGRAM=${NINJA} \
+ -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN} \
+ -DANDROID_NATIVE_API_LEVEL=${ANDROID_NATIVE_API_LEVEL} \
+ -DANDROID_TOOLCHAIN=clang \
+ -DANDROID_STL=c++_static \
+ -DANDROID_CPP_FEATURES=rtti\;exceptions \
+ \"
+}
+
+system_ndk || mason_ndk
diff --git a/platform/android/scripts/release.py b/platform/android/scripts/release.py
index bc485aa706..8abcccffdb 100644
--- a/platform/android/scripts/release.py
+++ b/platform/android/scripts/release.py
@@ -161,7 +161,7 @@ def abort_with_message(message):
def execute_call(command):
click.echo('Executing: %s' % command)
- result = subprocess.call(command.split(' '))
+ result = subprocess.call(command, shell=True)
if result != 0:
abort_with_message('Command failed: %s' % command)
diff --git a/platform/android/scripts/toolchain.sh b/platform/android/scripts/toolchain.sh
deleted file mode 100755
index a64818dd20..0000000000
--- a/platform/android/scripts/toolchain.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-set -o pipefail
-
-export MASON_PLATFORM=android
-export MASON_ANDROID_ABI=${1:-arm-v7}
-export PATH="`pwd`/.mason:${PATH}"
-export MASON_DIR="`pwd`/.mason"
-
-export PATH=`mason env PATH`
-
-echo "set(CMAKE_SYSTEM_NAME Android)"
-echo "set(CMAKE_SYSTEM_VERSION 1)"
-echo "set(CMAKE_CXX_COMPILER \"`which $(mason env CXX)`\")"
-echo "set(CMAKE_C_COMPILER \"`which $(mason env CC)`\")"
-echo "set(ANDROID_JNIDIR \"`mason env JNIDIR`\")"
-echo "set(ANDROID_ABI \"\${ANDROID_JNIDIR}\")"
-echo "set(CMAKE_EXE_LINKER_FLAGS \"`mason env LDFLAGS` \${CMAKE_EXE_LINKER_FLAGS}\")"
-echo "set(CMAKE_SHARED_LINKER_FLAGS \"`mason env LDFLAGS` \${CMAKE_SHARED_LINKER_FLAGS}\")"
-echo "set(CMAKE_CXX_FLAGS \"`mason env CXXFLAGS` \${CMAKE_CXX_FLAGS}\")"
-echo "set(CMAKE_C_FLAGS \"`mason env CPPFLAGS` \${CMAKE_C_FLAGS}\")"
-echo "set(STRIP_COMMAND \"`which $(mason env STRIP)`\")"
diff --git a/platform/android/src/annotation/marker.cpp b/platform/android/src/annotation/marker.cpp
new file mode 100644
index 0000000000..a1fe436dbd
--- /dev/null
+++ b/platform/android/src/annotation/marker.cpp
@@ -0,0 +1,31 @@
+#include "marker.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Marker> Marker::javaClass;
+
+mbgl::Point<double> Marker::getPosition(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto positionField = Marker::javaClass.GetField<jni::Object<LatLng>>(env, "position");
+ auto jPosition = marker.Get(env, positionField);
+ auto position = LatLng::getGeometry(env, jPosition);
+ jni::DeleteLocalRef(env, jPosition);
+ return position;
+}
+
+std::string Marker::getIconId(jni::JNIEnv& env, jni::Object<Marker> marker) {
+ static auto iconIdField = Marker::javaClass.GetField<jni::String>(env, "iconId");
+ auto jIconId = marker.Get(env, iconIdField);
+ auto iconId = jni::Make<std::string>(env, jIconId);
+ jni::DeleteLocalRef(env, jIconId);
+ return iconId;
+}
+
+void Marker::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Marker::javaClass = *jni::Class<Marker>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/marker.hpp b/platform/android/src/annotation/marker.hpp
new file mode 100644
index 0000000000..b11a225245
--- /dev/null
+++ b/platform/android/src/annotation/marker.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include <string>
+
+#include "../geometry/lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Marker : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Marker"; };
+
+ static jni::Class<Marker> javaClass;
+
+ static mbgl::Point<double> getPosition(jni::JNIEnv&, jni::Object<Marker>);
+
+ static std::string getIconId(jni::JNIEnv&, jni::Object<Marker>);
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/multi_point.hpp b/platform/android/src/annotation/multi_point.hpp
new file mode 100644
index 0000000000..e1152dfd60
--- /dev/null
+++ b/platform/android/src/annotation/multi_point.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class MultiPoint : protected mbgl::util::noncopyable {
+
+protected:
+
+ template <class Geometry>
+ static Geometry toGeometry(JNIEnv& env, jni::Object<java::util::List> pointsList) {
+ NullCheck(env, &pointsList);
+ auto jarray = java::util::List::toArray<LatLng>(env, pointsList);
+ NullCheck(env, &jarray);
+
+ std::size_t size = jarray.Length(env);
+
+ Geometry geometry;
+ geometry.reserve(size);
+
+ for (std::size_t i = 0; i < size; i++) {
+ auto latLng = jarray.Get(env, i);
+ NullCheck(env, &latLng);
+
+ geometry.push_back(LatLng::getGeometry(env, latLng));
+
+ jni::DeleteLocalRef(env, latLng);
+ }
+
+ jni::DeleteLocalRef(env, jarray);
+ return geometry;
+ }
+};
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polygon.cpp b/platform/android/src/annotation/polygon.cpp
new file mode 100644
index 0000000000..ba82fc34dc
--- /dev/null
+++ b/platform/android/src/annotation/polygon.cpp
@@ -0,0 +1,49 @@
+#include "polygon.hpp"
+
+#include "../conversion/color.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Polygon> Polygon::javaClass;
+
+mbgl::FillAnnotation Polygon::toAnnotation(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ auto points = Polygon::getPoints(env, polygon);
+
+ mbgl::FillAnnotation annotation { mbgl::Polygon<double> { MultiPoint::toGeometry<mbgl::LinearRing<double>>(env, points) } };
+ annotation.opacity = { Polygon::getOpacity(env, polygon) };
+ annotation.color = { Polygon::getFillColor(env, polygon) };
+ annotation.outlineColor = { Polygon::getOutlineColor(env, polygon) };
+
+ jni::DeleteLocalRef(env, points);
+
+ return annotation;
+}
+
+jni::Object<java::util::List> Polygon::getPoints(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polygon.Get(env, field);
+}
+
+float Polygon::getOpacity(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<float>(env, "alpha");
+ return polygon.Get(env, field);
+}
+
+mbgl::Color Polygon::getFillColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "fillColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+mbgl::Color Polygon::getOutlineColor(jni::JNIEnv& env, jni::Object<Polygon> polygon) {
+ static auto field = Polygon::javaClass.GetField<int>(env, "strokeColor");
+ return *conversion::convert<mbgl::Color, int>(env, polygon.Get(env, field));
+}
+
+void Polygon::registerNative(jni::JNIEnv& env) {
+ Polygon::javaClass = *jni::Class<Polygon>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polygon.hpp b/platform/android/src/annotation/polygon.hpp
new file mode 100644
index 0000000000..658aa5344b
--- /dev/null
+++ b/platform/android/src/annotation/polygon.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#include "multi_point.hpp"
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Polygon : private MultiPoint {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polygon"; };
+
+ static jni::Class<Polygon> javaClass;
+
+ static mbgl::FillAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getFillColor(jni::JNIEnv&, jni::Object<Polygon>);
+
+ static mbgl::Color getOutlineColor(jni::JNIEnv&, jni::Object<Polygon>);
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polyline.cpp b/platform/android/src/annotation/polyline.cpp
new file mode 100644
index 0000000000..3723dc1871
--- /dev/null
+++ b/platform/android/src/annotation/polyline.cpp
@@ -0,0 +1,49 @@
+#include "polyline.hpp"
+
+#include "../conversion/color.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Class<Polyline> Polyline::javaClass;
+
+mbgl::LineAnnotation Polyline::toAnnotation(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ auto points = Polyline::getPoints(env, polyline);
+
+ mbgl::LineAnnotation annotation { MultiPoint::toGeometry<mbgl::LineString<double>>(env, points) };
+ annotation.opacity = { Polyline::getOpacity(env, polyline) };
+ annotation.color = { Polyline::getColor(env, polyline) };
+ annotation.width = { Polyline::getWidth(env, polyline) };
+
+ jni::DeleteLocalRef(env, points);
+
+ return annotation;
+}
+
+jni::Object<java::util::List> Polyline::getPoints(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<jni::Object<java::util::List>>(env, "points");
+ return polyline.Get(env, field);
+}
+
+float Polyline::getOpacity(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "alpha");
+ return polyline.Get(env, field);
+}
+
+mbgl::Color Polyline::getColor(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<int>(env, "color");
+ return *conversion::convert<mbgl::Color, int>(env, polyline.Get(env, field));
+}
+
+float Polyline::getWidth(jni::JNIEnv& env, jni::Object<Polyline> polyline) {
+ static auto field = Polyline::javaClass.GetField<float>(env, "width");
+ return polyline.Get(env, field);
+}
+
+void Polyline::registerNative(jni::JNIEnv& env) {
+ Polyline::javaClass = *jni::Class<Polyline>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/annotation/polyline.hpp b/platform/android/src/annotation/polyline.hpp
new file mode 100644
index 0000000000..bcc616a5f7
--- /dev/null
+++ b/platform/android/src/annotation/polyline.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <string>
+
+#include "multi_point.hpp"
+
+#include "../geometry/lat_lng.hpp"
+#include "../java/util.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Polyline : private MultiPoint {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/annotations/Polyline"; };
+
+ static jni::Class<Polyline> javaClass;
+
+ static mbgl::LineAnnotation toAnnotation(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ static jni::Object<java::util::List> getPoints(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getOpacity(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static mbgl::Color getColor(jni::JNIEnv&, jni::Object<Polyline>);
+
+ static float getWidth(jni::JNIEnv&, jni::Object<Polyline>);
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/bitmap.cpp b/platform/android/src/bitmap.cpp
new file mode 100644
index 0000000000..50088116f4
--- /dev/null
+++ b/platform/android/src/bitmap.cpp
@@ -0,0 +1,132 @@
+#include "bitmap.hpp"
+
+#include <android/bitmap.h>
+
+namespace mbgl {
+namespace android {
+
+class PixelGuard {
+public:
+ PixelGuard(jni::JNIEnv& env_, jni::Object<Bitmap> bitmap_) : env(env_), bitmap(bitmap_) {
+ const int result = AndroidBitmap_lockPixels(&env, jni::Unwrap(*bitmap),
+ reinterpret_cast<void**>(&address));
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ throw std::runtime_error("bitmap decoding: could not lock pixels");
+ }
+ }
+ ~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");
+ }
+ }
+
+ auto* get() {
+ return address;
+ }
+
+ const auto* get() const {
+ return address;
+ }
+
+private:
+ jni::JNIEnv& env;
+ jni::Object<Bitmap> bitmap;
+ uint8_t* address;
+};
+
+void Bitmap::Config::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<Config>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Bitmap::Config> Bitmap::Config::_class;
+
+jni::Object<Bitmap::Config> Bitmap::Config::Create(jni::JNIEnv& env, Value value) {
+ switch (value) {
+ case ALPHA_8:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ALPHA_8"));
+ case ARGB_4444:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ARGB_4444"));
+ case ARGB_8888:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "ARGB_8888"));
+ case RGB_565:
+ return _class.Get(env,
+ jni::StaticField<Config, jni::Object<Config>>(env, _class, "RGB_565"));
+ default:
+ throw std::runtime_error("invalid enum value for Bitmap.Config");
+ }
+}
+
+void Bitmap::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<Bitmap>::Find(env).NewGlobalRef(env).release();
+ Config::registerNative(env);
+}
+
+jni::Class<Bitmap> Bitmap::_class;
+
+jni::Object<Bitmap> Bitmap::CreateBitmap(jni::JNIEnv& env,
+ jni::jint width,
+ jni::jint height,
+ jni::Object<Config> config) {
+ using Signature = jni::Object<Bitmap>(jni::jint, jni::jint, jni::Object<Config>);
+ auto method = _class.GetStaticMethod<Signature>(env, "createBitmap");
+ return _class.Call(env, method, width, height, config);
+}
+
+jni::Object<Bitmap> Bitmap::CreateBitmap(jni::JNIEnv& env, const PremultipliedImage& image) {
+ auto bitmap = CreateBitmap(env, image.size.width, image.size.height, Config::ARGB_8888);
+
+ AndroidBitmapInfo info;
+ const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info);
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ // TODO: more specific information
+ throw std::runtime_error("bitmap creation: couldn't get bitmap info");
+ }
+
+ assert(info.width == image.size.width);
+ assert(info.height == image.size.height);
+ assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
+
+ PixelGuard guard(env, bitmap);
+
+ // Copy the PremultipliedImage into the Android Bitmap
+ for (uint32_t y = 0; y < image.size.height; y++) {
+ auto begin = image.data.get() + y * image.stride();
+ std::copy(begin, begin + image.stride(), guard.get() + y * info.stride);
+ }
+
+ return bitmap;
+}
+
+PremultipliedImage Bitmap::GetImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) {
+ AndroidBitmapInfo info;
+ const int result = AndroidBitmap_getInfo(&env, jni::Unwrap(*bitmap), &info);
+ if (result != ANDROID_BITMAP_RESULT_SUCCESS) {
+ // TODO: more specific information
+ throw std::runtime_error("bitmap decoding: couldn't get bitmap info");
+ }
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
+ // TODO: convert
+ throw std::runtime_error("bitmap decoding: bitmap format invalid");
+ }
+
+ const PixelGuard guard(env, bitmap);
+
+ // Copy the Android Bitmap into the PremultipliedImage.
+ auto pixels =
+ std::make_unique<uint8_t[]>(info.width * info.height * PremultipliedImage::channels);
+ for (uint32_t y = 0; y < info.height; y++) {
+ auto begin = guard.get() + y * info.stride;
+ std::copy(begin, begin + info.width * PremultipliedImage::channels,
+ pixels.get() + y * info.width * PremultipliedImage::channels);
+ }
+
+ return { Size{ info.width, info.height }, std::move(pixels) };
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap.hpp b/platform/android/src/bitmap.hpp
new file mode 100644
index 0000000000..f64f42ae87
--- /dev/null
+++ b/platform/android/src/bitmap.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <mbgl/util/image.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Bitmap {
+public:
+ class Config {
+ public:
+ static constexpr auto Name() {
+ return "android/graphics/Bitmap$Config";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ enum Value {
+ ALPHA_8,
+ ARGB_4444,
+ ARGB_8888,
+ RGB_565,
+ };
+
+ static jni::Object<Config> Create(jni::JNIEnv&, Value);
+
+ private:
+ static jni::Class<Config> _class;
+ };
+
+ static constexpr auto Name() {
+ return "android/graphics/Bitmap";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::Object<Bitmap>
+ CreateBitmap(jni::JNIEnv&, jni::jint width, jni::jint height, jni::Object<Config>);
+ static jni::Object<Bitmap>
+ CreateBitmap(jni::JNIEnv& env, jni::jint width, jni::jint height, Config::Value config) {
+ return CreateBitmap(env, width, height, Config::Create(env, config));
+ }
+
+ static PremultipliedImage GetImage(jni::JNIEnv&, jni::Object<Bitmap>);
+ static jni::Object<Bitmap> CreateBitmap(jni::JNIEnv&, const PremultipliedImage&);
+
+private:
+ static jni::Class<Bitmap> _class;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap_factory.cpp b/platform/android/src/bitmap_factory.cpp
new file mode 100644
index 0000000000..7d9b068b20
--- /dev/null
+++ b/platform/android/src/bitmap_factory.cpp
@@ -0,0 +1,25 @@
+#include "bitmap_factory.hpp"
+
+namespace mbgl {
+namespace android {
+
+void BitmapFactory::registerNative(jni::JNIEnv& env) {
+ _class = *jni::Class<BitmapFactory>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<BitmapFactory> BitmapFactory::_class;
+
+jni::Object<Bitmap> BitmapFactory::DecodeByteArray(jni::JNIEnv& env,
+ jni::Array<jni::jbyte> data,
+ jni::jint offset,
+ jni::jint length) {
+
+ // Images are loaded with ARGB_8888 config, and premultiplied by default, which is exactly
+ // what we want, so we're not providing a BitmapFactory.Options object.
+ using Signature = jni::Object<Bitmap>(jni::Array<jni::jbyte>, jni::jint, jni::jint);
+ auto method = _class.GetStaticMethod<Signature>(env, "decodeByteArray");
+ return _class.Call(env, method, data, offset, length);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/bitmap_factory.hpp b/platform/android/src/bitmap_factory.hpp
new file mode 100644
index 0000000000..b0e7198260
--- /dev/null
+++ b/platform/android/src/bitmap_factory.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include "bitmap.hpp"
+
+namespace mbgl {
+namespace android {
+
+class BitmapFactory {
+public:
+ static constexpr auto Name() {
+ return "android/graphics/BitmapFactory";
+ };
+ static void registerNative(jni::JNIEnv&);
+
+ static jni::Object<Bitmap>
+ DecodeByteArray(jni::JNIEnv&, jni::Array<jni::jbyte> data, jni::jint offset, jni::jint length);
+
+private:
+ static jni::Class<BitmapFactory> _class;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/connectivity_listener.cpp b/platform/android/src/connectivity_listener.cpp
index cc2f0a4a81..5b1c0a86e4 100644
--- a/platform/android/src/connectivity_listener.cpp
+++ b/platform/android/src/connectivity_listener.cpp
@@ -22,12 +22,12 @@ namespace android {
jni::Class<ConnectivityListener> ConnectivityListener::javaClass;
void ConnectivityListener::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
ConnectivityListener::javaClass = *jni::Class<ConnectivityListener>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<ConnectivityListener>(
env,
ConnectivityListener::javaClass,
@@ -39,5 +39,5 @@ namespace android {
);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/connectivity_listener.hpp b/platform/android/src/connectivity_listener.hpp
index d457dcfd5a..b0d655d027 100644
--- a/platform/android/src/connectivity_listener.hpp
+++ b/platform/android/src/connectivity_listener.hpp
@@ -27,9 +27,5 @@ public:
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp
index 4256d5f969..da5eed64d2 100644
--- a/platform/android/src/conversion/collection.hpp
+++ b/platform/android/src/conversion/collection.hpp
@@ -32,6 +32,20 @@ inline std::vector<std::string> toVector(JNIEnv& env, jni::jarray<jni::jobject>&
for (std::size_t i = 0; i < len; i++) {
jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(env, array, i));
vector.push_back(*convert<std::string, jni::String>(env, jni::String(jstr)));
+ jni::DeleteLocalRef(env, jstr);
+ }
+
+ return vector;
+}
+
+inline std::vector<std::string> toVector(JNIEnv& env, jni::Array<jni::String> array) {
+ std::vector<std::string> vector;
+ std::size_t len = array.Length(env);
+
+ for (std::size_t i = 0; i < len; i++) {
+ jni::String jstr = array.Get(env, i);
+ vector.push_back(*convert<std::string, jni::String>(env, jstr));
+ jni::DeleteLocalRef(env, jstr);
}
return vector;
diff --git a/platform/android/src/conversion/color.hpp b/platform/android/src/conversion/color.hpp
new file mode 100644
index 0000000000..40aa68d4a9
--- /dev/null
+++ b/platform/android/src/conversion/color.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "conversion.hpp"
+
+#include <mbgl/util/color.hpp>
+
+namespace mbgl {
+namespace android {
+namespace conversion {
+
+template <>
+struct Converter<mbgl::Color, int> {
+ Result<mbgl::Color> operator()(jni::JNIEnv&, const int& color) const {
+ float r = (color >> 16) & 0xFF;
+ float g = (color >> 8) & 0xFF;
+ float b = (color) & 0xFF;
+ float a = (color >> 24) & 0xFF;
+ return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) };
+ }
+};
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index f1a8171b99..2a0b710f73 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -76,7 +76,7 @@ struct Converter<jni::jobject*, T, typename std::enable_if<std::is_integral<T>::
}
};
-//TODO: convert integral types to primitive jni types
+// TODO: convert integral types to primitive jni types
template <>
struct Converter<jni::jobject*, std::string> {
diff --git a/platform/android/src/conversion/conversion.hpp b/platform/android/src/conversion/conversion.hpp
index 1277f3f67e..d1766f9755 100644
--- a/platform/android/src/conversion/conversion.hpp
+++ b/platform/android/src/conversion/conversion.hpp
@@ -47,4 +47,4 @@ Result<T> convert(jni::JNIEnv& env, const V& value, Args&&...args) {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
new file mode 100644
index 0000000000..30e1ff50fe
--- /dev/null
+++ b/platform/android/src/file_source.cpp
@@ -0,0 +1,106 @@
+#include "file_source.hpp"
+
+#include <mbgl/util/logging.hpp>
+
+#include <string>
+
+#include "jni/generic_global_ref_deleter.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+// FileSource //
+
+FileSource::FileSource(jni::JNIEnv& _env, jni::String accessToken, jni::String _cachePath, jni::String _apkPath) {
+ // Create a core default file source
+ fileSource = std::make_unique<mbgl::DefaultFileSource>(
+ jni::Make<std::string>(_env, _cachePath) + "/mbgl-offline.db",
+ jni::Make<std::string>(_env, _apkPath));
+
+ // Set access token
+ fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken));
+}
+
+FileSource::~FileSource() {
+}
+
+jni::String FileSource::getAccessToken(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, fileSource->getAccessToken());
+}
+
+void FileSource::setAccessToken(jni::JNIEnv& env, jni::String token) {
+ fileSource->setAccessToken(jni::Make<std::string>(env, token));
+}
+
+void FileSource::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) {
+ fileSource->setAPIBaseURL(jni::Make<std::string>(env, url));
+}
+
+void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> transformCallback) {
+ if (transformCallback) {
+ // Launch transformCallback
+ fileSource->setResourceTransform([
+ // Capture the ResourceTransformCallback object as a managed global into
+ // the lambda. It is released automatically when we're setting a new ResourceTransform in
+ // a subsequent call.
+ // Note: we're converting it to shared_ptr because this lambda is converted to a std::function,
+ // which requires copyability of its captured variables.
+ callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()),
+ env
+ ](mbgl::Resource::Kind kind, std::string&& url_) {
+ return FileSource::ResourceTransformCallback::onURL(const_cast<jni::JNIEnv&>(env), jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
+ });
+ } else {
+ // Reset the callback
+ fileSource->setResourceTransform(nullptr);
+ }
+}
+
+jni::Class<FileSource> FileSource::javaClass;
+
+FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ static auto field = FileSource::javaClass.GetField<jlong>(env, "nativePtr");
+ return reinterpret_cast<FileSource *>(jFileSource.Get(env, field));
+}
+
+mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
+ FileSource* fileSource = FileSource::getNativePeer(env, jFileSource);
+ assert(fileSource != nullptr);
+ return *fileSource->fileSource;
+}
+
+void FileSource::registerNative(jni::JNIEnv& env) {
+ //Register classes
+ FileSource::javaClass = *jni::Class<FileSource>::Find(env).NewGlobalRef(env).release();
+ FileSource::ResourceTransformCallback::javaClass = *jni::Class<FileSource::ResourceTransformCallback>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<FileSource>(
+ env, FileSource::javaClass, "nativePtr",
+ std::make_unique<FileSource, JNIEnv&, jni::String, jni::String, jni::String>,
+ "initialize",
+ "finalize",
+ METHOD(&FileSource::getAccessToken, "getAccessToken"),
+ METHOD(&FileSource::setAccessToken, "setAccessToken"),
+ METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
+ METHOD(&FileSource::setResourceTransform, "setResourceTransform")
+ );
+}
+
+
+// FileSource::ResourceTransformCallback //
+
+jni::Class<FileSource::ResourceTransformCallback> FileSource::ResourceTransformCallback::javaClass;
+
+std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> callback, int kind, std::string url_) {
+ static auto method = FileSource::ResourceTransformCallback::javaClass.GetMethod<jni::String (jni::jint, jni::String)>(env, "onURL");
+ auto url = jni::Make<jni::String>(env, url_);
+ url = callback.Call(env, method, kind, url);
+ return jni::Make<std::string>(env, url);
+}
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
new file mode 100644
index 0000000000..073e393e05
--- /dev/null
+++ b/platform/android/src/file_source.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <mbgl/storage/default_file_source.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+/**
+ * Peer class for the Android FileSource holder. Ensures that a single DefaultFileSource is used
+ */
+class FileSource {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource"; };
+
+ struct ResourceTransformCallback {
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/storage/FileSource$ResourceTransformCallback"; }
+
+ static std::string onURL(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>, int, std::string);
+
+ static jni::Class<ResourceTransformCallback> javaClass;
+ };
+
+ FileSource(jni::JNIEnv&, jni::String, jni::String, jni::String);
+
+ ~FileSource();
+
+ jni::String getAccessToken(jni::JNIEnv&);
+
+ void setAccessToken(jni::JNIEnv&, jni::String);
+
+ void setAPIBaseUrl(jni::JNIEnv&, jni::String);
+
+ void setResourceTransform(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>);
+
+ static jni::Class<FileSource> javaClass;
+
+ static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, jni::Object<FileSource>);
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+
+ std::unique_ptr<mbgl::DefaultFileSource> fileSource;
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/conversion/feature.hpp b/platform/android/src/geometry/conversion/feature.hpp
index f0c77c3389..921138e859 100644
--- a/platform/android/src/geometry/conversion/feature.hpp
+++ b/platform/android/src/geometry/conversion/feature.hpp
@@ -3,6 +3,7 @@
#include "../../conversion/constant.hpp"
#include "../../conversion/conversion.hpp"
#include "geometry.hpp"
+#include "../../gson/json_object.hpp"
#include <mbgl/util/feature.hpp>
#include <mapbox/variant.hpp>
@@ -10,6 +11,7 @@
#include <jni/jni.hpp>
#include "../../jni/local_object.hpp"
+#include "../feature.hpp"
#include <string>
#include <array>
@@ -64,7 +66,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Boolean;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, bool>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted);
@@ -78,7 +80,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/String;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get());
@@ -93,7 +95,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Number;)V");
- //Create JsonPrimitive
+ // Create JsonPrimitive
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, Number>(env, value));
jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get());
@@ -109,10 +111,10 @@ public:
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V");
- //Create json array
+ // Create json array
jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor);
- //Add values
+ // Add values
for (const auto &v : values) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this));
jni::CallMethod<void>(env, jarray, *add, converted.get());
@@ -125,15 +127,15 @@ public:
* Json Object
*/
jni::jobject* operator()(const std::unordered_map<std::string, mbgl::Value> &value) const {
- //TODO: clean up duplication here
+ // TODO: clean up duplication here
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
- //Create json object
+ // Create json object
jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
- //Add items
+ // Add items
for (auto &item : value) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this));
jni::LocalObject<jni::jobject> key = jni::NewLocalObject(env, *convert<jni::jobject*, std::string>(env, item.first));
@@ -151,10 +153,10 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "()V");;
static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V");
- //Create json object
+ // Create json object
jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor);
- //Add items
+ // Add items
PropertyValueEvaluator evaluator {env};
for (auto &item : value) {
jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator));
@@ -168,39 +170,45 @@ struct Converter<jni::jobject*, std::unordered_map<std::string, mbgl::Value>> {
template <>
-struct Converter<jni::jobject*, mbgl::Feature> {
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
- static jni::jmethodID* fromGeometry = &jni::GetStaticMethodID(env, *javaClass, "fromGeometry", "(Lcom/mapbox/services/commons/geojson/Geometry;Lcom/google/gson/JsonObject;Ljava/lang/String;)Lcom/mapbox/services/commons/geojson/Feature;");
+struct Converter<jni::Object<Feature>, mbgl::Feature> {
+ Result<jni::Object<Feature>> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const {
- //Convert Id
+ // Convert Id
FeatureIdVisitor idEvaluator;
std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : "";
- jni::LocalObject<jni::jobject> jid = jni::NewLocalObject(env, *convert<jni::jobject*>(env, id));
+ auto jid = jni::Make<jni::String>(env, id);
- //Convert properties
- jni::LocalObject<jni::jobject> properties = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.properties));
+ // Convert properties
+ auto properties = jni::Object<JsonObject>(*convert<jni::jobject*>(env, value.properties));
- //Convert geometry
- jni::LocalObject<jni::jobject> geometry = jni::NewLocalObject(env, *convert<jni::jobject*>(env, value.geometry));
+ // Convert geometry
+ auto geometry = jni::Object<Geometry>(*convert<jni::jobject*>(env, value.geometry));
- //Create feature
- return {reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometry, geometry.get(), properties.get(), jid.get()))};
+ // Create feature
+ auto feature = Feature::fromGeometry(env, geometry, properties, jid);
+
+ //Cleanup
+ jni::DeleteLocalRef(env, jid);
+ jni::DeleteLocalRef(env, geometry);
+ jni::DeleteLocalRef(env, properties);
+
+ return feature;
}
};
template <>
-struct Converter<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>> {
- Result<jni::jarray<jni::jobject>*> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
- static jni::jclass* featureClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Feature")).release();
- jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *featureClass);
+struct Converter<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>> {
+ Result<jni::Array<jni::Object<Feature>>> operator()(jni::JNIEnv& env, const std::vector<mbgl::Feature>& value) const {
+
+ auto features = jni::Array<jni::Object<Feature>>::New(env, value.size(), Feature::javaClass);
for(size_t i = 0; i < value.size(); i = i + 1) {
- jni::LocalObject<jni::jobject> converted = jni::NewLocalObject(env, *convert<jni::jobject*, mbgl::Feature>(env, value.at(i)));
- jni::SetObjectArrayElement(env, jarray, i, converted.get());
+ auto converted = *convert<jni::Object<Feature>, mbgl::Feature>(env, value.at(i));
+ features.Set(env, i, converted);
+ jni::DeleteLocalRef(env, converted);
}
- return {&jarray};
+ return {features};
}
};
diff --git a/platform/android/src/geometry/conversion/geometry.hpp b/platform/android/src/geometry/conversion/geometry.hpp
index 385ba9034e..2ca63e2c11 100644
--- a/platform/android/src/geometry/conversion/geometry.hpp
+++ b/platform/android/src/geometry/conversion/geometry.hpp
@@ -27,7 +27,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Point")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([D)Lcom/mapbox/services/commons/geojson/Point;");
- //Create Point
+ // Create Point
jni::LocalObject<jni::jarray<jni::jdouble>> position = jni::NewLocalObject(env, toGeoJsonPosition(env, geometry.x, geometry.y));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, position.get()));
}
@@ -39,7 +39,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/LineString")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/LineString;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get()));
}
@@ -51,7 +51,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPoint")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[D)Lcom/mapbox/services/commons/geojson/MultiPoint;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> coordinates = jni::NewLocalObject(env, toGeoJsonCoordinates(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, coordinates.get()));
}
@@ -63,7 +63,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/Polygon")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/Polygon;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get()));
}
@@ -75,7 +75,7 @@ public:
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiLineString")).release();
static jni::jmethodID* fromCoordinates = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[D)Lcom/mapbox/services/commons/geojson/MultiLineString;");
- //Create
+ // Create
jni::LocalObject<jni::jarray<jni::jobject>> shape = jni::NewLocalObject(env, toShape<>(env, geometry));
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromCoordinates, shape.get()));
}
@@ -92,7 +92,7 @@ public:
jni::SetObjectArrayElement(env, *jarray, i, shape.get());
}
- //Create the MultiPolygon
+ // Create the MultiPolygon
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/MultiPolygon")).release();
static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromCoordinates", "([[[[D)Lcom/mapbox/services/commons/geojson/MultiPolygon;");
return reinterpret_cast<jni::jobject*>(jni::CallStaticMethod<jni::jobject*>(env, *javaClass, *fromGeometries, jarray.get()));
@@ -111,7 +111,7 @@ public:
jni::SetObjectArrayElement(env, *jarray, i, converted.get());
}
- //Turn into array list and create the GeometryCollection
+ // Turn into array list and create the GeometryCollection
static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/services/commons/geojson/GeometryCollection")).release();
static jni::jmethodID* fromGeometries = &jni::GetStaticMethodID(env, *javaClass, "fromGeometries", "(Ljava/util/List;)Lcom/mapbox/services/commons/geojson/GeometryCollection;");
diff --git a/platform/android/src/geometry/feature.cpp b/platform/android/src/geometry/feature.cpp
new file mode 100644
index 0000000000..5355d50ab7
--- /dev/null
+++ b/platform/android/src/geometry/feature.cpp
@@ -0,0 +1,20 @@
+#include "feature.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<Feature> Feature::fromGeometry(jni::JNIEnv& env, jni::Object<Geometry> geometry, jni::Object<JsonObject> properties, jni::String id) {
+ static auto method = Feature::javaClass.GetStaticMethod<jni::Object<Feature> (jni::Object<Geometry>, jni::Object<JsonObject>, jni::String)>(env, "fromGeometry");
+ return Feature::javaClass.Call(env, method, geometry, properties, id);
+}
+
+void Feature::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ Feature::javaClass = *jni::Class<Feature>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<Feature> Feature::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/feature.hpp b/platform/android/src/geometry/feature.hpp
new file mode 100644
index 0000000000..7f2733430c
--- /dev/null
+++ b/platform/android/src/geometry/feature.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+#include "geometry.hpp"
+#include "../gson/json_object.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Feature : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Feature"; };
+
+ static jni::Object<Feature> fromGeometry(jni::JNIEnv&, jni::Object<Geometry>, jni::Object<JsonObject>, jni::String);
+
+ static jni::Class<Feature> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/geometry.hpp b/platform/android/src/geometry/geometry.hpp
new file mode 100644
index 0000000000..5c8ae39181
--- /dev/null
+++ b/platform/android/src/geometry/geometry.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Geometry : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/services/commons/geojson/Geometry"; };
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng.cpp b/platform/android/src/geometry/lat_lng.cpp
new file mode 100644
index 0000000000..9cf3630107
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng.cpp
@@ -0,0 +1,31 @@
+#include "lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLng> LatLng::New(jni::JNIEnv& env, double latitude, double longitude) {
+ static auto constructor = LatLng::javaClass.GetConstructor<double, double>(env);
+ return LatLng::javaClass.New(env, constructor, latitude, longitude);
+}
+
+mbgl::Point<double> LatLng::getGeometry(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
+ static auto latitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "latitude");
+ static auto longitudeField = LatLng::javaClass.GetField<jni::jdouble>(env, "longitude");
+ return mbgl::Point<double>(latLng.Get(env, longitudeField), latLng.Get(env, latitudeField));
+}
+
+mbgl::LatLng LatLng::getLatLng(jni::JNIEnv& env, jni::Object<LatLng> latLng) {
+ auto point = LatLng::getGeometry(env, latLng);
+ return mbgl::LatLng(point.y, point.x);
+}
+
+void LatLng::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLng::javaClass = *jni::Class<LatLng>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLng> LatLng::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng.hpp b/platform/android/src/geometry/lat_lng.hpp
new file mode 100644
index 0000000000..1ac32ae32e
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLng : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLng"; };
+
+ static jni::Object<LatLng> New(jni::JNIEnv&, double, double);
+
+ static mbgl::Point<double> getGeometry(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static mbgl::LatLng getLatLng(jni::JNIEnv&, jni::Object<LatLng>);
+
+ static jni::Class<LatLng> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.cpp b/platform/android/src/geometry/lat_lng_bounds.cpp
new file mode 100644
index 0000000000..9efacde120
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.cpp
@@ -0,0 +1,31 @@
+#include "lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLngBounds> LatLngBounds::New(jni::JNIEnv& env, mbgl::LatLngBounds bounds) {
+ static auto constructor = LatLngBounds::javaClass.GetConstructor<double, double, double, double>(env);
+ return LatLngBounds::javaClass.New(env, constructor, bounds.north(), bounds.east(), bounds.south(), bounds.west());
+}
+
+mbgl::LatLngBounds LatLngBounds::getLatLngBounds(jni::JNIEnv& env, jni::Object<LatLngBounds> bounds) {
+ static auto swLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatSouth");
+ static auto swLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonWest");
+ static auto neLat = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLatNorth");
+ static auto neLon = LatLngBounds::javaClass.GetField<jni::jdouble>(env, "mLonEast");
+ return mbgl::LatLngBounds::hull(
+ { bounds.Get(env, swLat), bounds.Get(env, swLon) },
+ { bounds.Get(env, neLat), bounds.Get(env, neLon) }
+ );
+}
+
+void LatLngBounds::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLngBounds::javaClass = *jni::Class<LatLngBounds>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLngBounds> LatLngBounds::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_bounds.hpp b/platform/android/src/geometry/lat_lng_bounds.hpp
new file mode 100644
index 0000000000..1c853e4b67
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_bounds.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class LatLngBounds : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngBounds"; };
+
+ static jni::Object<LatLngBounds> New(jni::JNIEnv&, mbgl::LatLngBounds);
+
+ static mbgl::LatLngBounds getLatLngBounds(jni::JNIEnv&, jni::Object<LatLngBounds>);
+
+ static jni::Class<LatLngBounds> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/projected_meters.cpp b/platform/android/src/geometry/projected_meters.cpp
new file mode 100644
index 0000000000..f3d9d1b0ef
--- /dev/null
+++ b/platform/android/src/geometry/projected_meters.cpp
@@ -0,0 +1,20 @@
+#include "projected_meters.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<ProjectedMeters> ProjectedMeters::New(jni::JNIEnv& env, double northing, double easting) {
+ static auto constructor = ProjectedMeters::javaClass.GetConstructor<double, double>(env);
+ return ProjectedMeters::javaClass.New(env, constructor, northing, easting);
+}
+
+void ProjectedMeters::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ ProjectedMeters::javaClass = *jni::Class<ProjectedMeters>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<ProjectedMeters> ProjectedMeters::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/projected_meters.hpp b/platform/android/src/geometry/projected_meters.hpp
new file mode 100644
index 0000000000..9b70967b5d
--- /dev/null
+++ b/platform/android/src/geometry/projected_meters.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class ProjectedMeters : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/ProjectedMeters"; };
+
+ static jni::Object<ProjectedMeters> New(jni::JNIEnv&, double, double);
+
+ static jni::Class<ProjectedMeters> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/pointf.cpp b/platform/android/src/graphics/pointf.cpp
new file mode 100644
index 0000000000..6e91b81416
--- /dev/null
+++ b/platform/android/src/graphics/pointf.cpp
@@ -0,0 +1,20 @@
+#include "pointf.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<PointF> PointF::New(jni::JNIEnv& env, float x, float y) {
+ static auto constructor = PointF::javaClass.GetConstructor<float, float>(env);
+ return PointF::javaClass.New(env, constructor, x, y);
+}
+
+void PointF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ PointF::javaClass = *jni::Class<PointF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<PointF> PointF::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/pointf.hpp b/platform/android/src/graphics/pointf.hpp
new file mode 100644
index 0000000000..ea25ad2b40
--- /dev/null
+++ b/platform/android/src/graphics/pointf.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class PointF : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "android/graphics/PointF"; };
+
+ static jni::Object<PointF> New(jni::JNIEnv&, float, float);
+
+ static jni::Class<PointF> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/rectf.cpp b/platform/android/src/graphics/rectf.cpp
new file mode 100644
index 0000000000..1b375dad18
--- /dev/null
+++ b/platform/android/src/graphics/rectf.cpp
@@ -0,0 +1,35 @@
+#include "rectf.hpp"
+
+namespace mbgl {
+namespace android {
+
+float RectF::getLeft(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "left");
+ return rectf.Get(env, field);
+}
+
+float RectF::getTop(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "top");
+ return rectf.Get(env, field);
+}
+
+float RectF::getRight(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "right");
+ return rectf.Get(env, field);
+}
+
+float RectF::getBottom(jni::JNIEnv& env, jni::Object<RectF> rectf) {
+ static auto field = RectF::javaClass.GetField<float>(env, "bottom");
+ return rectf.Get(env, field);
+}
+
+void RectF::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ RectF::javaClass = *jni::Class<RectF>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<RectF> RectF::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/graphics/rectf.hpp b/platform/android/src/graphics/rectf.hpp
new file mode 100644
index 0000000000..0f3a7756d5
--- /dev/null
+++ b/platform/android/src/graphics/rectf.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class RectF : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "android/graphics/RectF"; };
+
+ static float getLeft(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getTop(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getRight(jni::JNIEnv&, jni::Object<RectF>);
+
+ static float getBottom(jni::JNIEnv&, jni::Object<RectF>);
+
+ static jni::Class<RectF> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/gson/json_object.hpp b/platform/android/src/gson/json_object.hpp
new file mode 100644
index 0000000000..a7de0b1978
--- /dev/null
+++ b/platform/android/src/gson/json_object.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+namespace mbgl {
+namespace android {
+
+class JsonObject : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/google/gson/JsonObject"; };
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/image.cpp b/platform/android/src/image.cpp
new file mode 100644
index 0000000000..2a33944b18
--- /dev/null
+++ b/platform/android/src/image.cpp
@@ -0,0 +1,22 @@
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <string>
+
+#include "attach_env.hpp"
+#include "bitmap_factory.hpp"
+
+namespace mbgl {
+
+PremultipliedImage decodeImage(const std::string& string) {
+ auto env{ android::AttachEnv() };
+
+ auto array = jni::Array<jni::jbyte>::New(*env, string.size());
+ jni::SetArrayRegion(*env, *array, 0, string.size(),
+ reinterpret_cast<const signed char*>(string.data()));
+
+ auto bitmap = android::BitmapFactory::DecodeByteArray(*env, array, 0, string.size());
+ return android::Bitmap::GetImage(*env, bitmap);
+}
+
+} // namespace mbgl
diff --git a/platform/android/src/java/lang.hpp b/platform/android/src/java/lang.hpp
new file mode 100644
index 0000000000..dcf81a9d0c
--- /dev/null
+++ b/platform/android/src/java/lang.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace lang {
+
+class Float {
+public:
+ static constexpr auto Name() { return "java/lang/Float"; };
+};
+
+class Number {
+public:
+ static constexpr auto Name() { return "java/lang/Number"; };
+};
+
+} // namespace lang
+} // namespace java
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/java/util.cpp b/platform/android/src/java/util.cpp
new file mode 100644
index 0000000000..c630e403d9
--- /dev/null
+++ b/platform/android/src/java/util.cpp
@@ -0,0 +1,18 @@
+#include "util.hpp"
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace util {
+
+jni::Class<List> List::javaClass;
+
+void registerNative(jni::JNIEnv& env) {
+ List::javaClass = *jni::Class<List>::Find(env).NewGlobalRef(env).release();
+}
+
+
+} // namespace util
+} // namespace java
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java/util.hpp b/platform/android/src/java/util.hpp
new file mode 100644
index 0000000000..1a552c7124
--- /dev/null
+++ b/platform/android/src/java/util.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+namespace java {
+namespace util {
+
+class List : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "java/util/List"; };
+
+ template<class T>
+ static jni::Array<jni::Object<T>> toArray(jni::JNIEnv& env, jni::Object<List> list) {
+ static auto toArray = List::javaClass.GetMethod<jni::Array<jni::Object<>> ()>(env, "toArray");
+ return (jni::Array<jni::Object<T>>) list.Call(env, toArray);
+ };
+
+ static jni::Class<List> javaClass;
+
+};
+
+void registerNative(jni::JNIEnv&);
+
+
+} // namespace util
+} // namespace java
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/java_types.hpp b/platform/android/src/java_types.hpp
index 2e2c5fc2d6..b416a75b91 100644
--- a/platform/android/src/java_types.hpp
+++ b/platform/android/src/java_types.hpp
@@ -32,4 +32,4 @@ namespace java {
void registerNatives(JNIEnv&);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 1ef7fec8fb..bd12cff3fa 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -1,44 +1,37 @@
-#include <cstdint>
-#include <cinttypes>
-#include <cassert>
-#include <string>
-#include <array>
-#include <vector>
+#include "jni.hpp"
-#include <android/native_window_jni.h>
-#include <sys/system_properties.h>
+#include <mbgl/util/logging.hpp>
-#include "jni.hpp"
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "bitmap.hpp"
+#include "bitmap_factory.hpp"
+#include "connectivity_listener.hpp"
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "file_source.hpp"
+#include "geometry/feature.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/lat_lng_bounds.hpp"
+#include "geometry/projected_meters.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
#include "java_types.hpp"
#include "native_map_view.hpp"
-#include "connectivity_listener.hpp"
+#include "offline/offline_manager.hpp"
+#include "offline/offline_region.hpp"
+#include "offline/offline_region_definition.hpp"
+#include "offline/offline_region_error.hpp"
+#include "offline/offline_region_status.hpp"
+#include "style/functions/categorical_stops.hpp"
+#include "style/functions/exponential_stops.hpp"
+#include "style/functions/identity_stops.hpp"
+#include "style/functions/interval_stops.hpp"
+#include "style/functions/stop.hpp"
#include "style/layers/layers.hpp"
#include "style/sources/sources.hpp"
-#include "conversion/conversion.hpp"
-#include "conversion/collection.hpp"
-#include "geometry/conversion/feature.hpp"
-
-#include <mbgl/map/map.hpp>
-#include <mbgl/map/camera.hpp>
-#include <mbgl/annotation/annotation.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/style/source.hpp>
-#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/storage/network_status.hpp>
-#include <mbgl/util/exception.hpp>
-#include <mbgl/util/optional.hpp>
-#include <mbgl/util/string.hpp>
-#include <mbgl/util/run_loop.hpp>
-
-#include <mapbox/geometry.hpp>
-
-#include <jni/jni.hpp>
-
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
namespace mbgl {
namespace android {
@@ -46,127 +39,7 @@ void RegisterNativeHTTPRequest(JNIEnv&);
JavaVM* theJVM;
-std::string cachePath;
-std::string dataPath;
-std::string apkPath;
-std::string androidRelease;
-
-jni::jmethodID* onInvalidateId = nullptr;
-jni::jmethodID* onMapChangedId = nullptr;
-jni::jmethodID* onFpsChangedId = nullptr;
-jni::jmethodID* onSnapshotReadyId = nullptr;
-
-jni::jclass* latLngClass = nullptr;
-jni::jmethodID* latLngConstructorId = nullptr;
-jni::jfieldID* latLngLatitudeId = nullptr;
-jni::jfieldID* latLngLongitudeId = nullptr;
-
-jni::jclass* latLngBoundsClass = nullptr;
-jni::jmethodID* latLngBoundsConstructorId = nullptr;
-jni::jfieldID* latLngBoundsLatNorthId = nullptr;
-jni::jfieldID* latLngBoundsLatSouthId = nullptr;
-jni::jfieldID* latLngBoundsLonEastId = nullptr;
-jni::jfieldID* latLngBoundsLonWestId = nullptr;
-
-jni::jclass* iconClass = nullptr;
-jni::jfieldID* iconIdId = nullptr;
-
-jni::jclass* markerClass = nullptr;
-jni::jfieldID* markerPositionId = nullptr;
-jni::jfieldID* markerIconId = nullptr;
-jni::jfieldID* markerIdId = nullptr;
-
-jni::jclass* polylineClass = nullptr;
-jni::jfieldID* polylineAlphaId = nullptr;
-jni::jfieldID* polylineColorId = nullptr;
-jni::jfieldID* polylineWidthId = nullptr;
-jni::jfieldID* polylinePointsId = nullptr;
-
-jni::jclass* polygonClass = nullptr;
-jni::jfieldID* polygonAlphaId = nullptr;
-jni::jfieldID* polygonFillColorId = nullptr;
-jni::jfieldID* polygonStrokeColorId = nullptr;
-jni::jfieldID* polygonPointsId = nullptr;
-
-jni::jmethodID* listToArrayId = nullptr;
-
-jni::jclass* arrayListClass = nullptr;
-jni::jmethodID* arrayListConstructorId = nullptr;
-jni::jmethodID* arrayListAddId = nullptr;
-
-jni::jclass* projectedMetersClass = nullptr;
-jni::jmethodID* projectedMetersConstructorId = nullptr;
-jni::jfieldID* projectedMetersNorthingId = nullptr;
-jni::jfieldID* projectedMetersEastingId = nullptr;
-
-jni::jclass* pointFClass = nullptr;
-jni::jmethodID* pointFConstructorId = nullptr;
-jni::jfieldID* pointFXId = nullptr;
-jni::jfieldID* pointFYId = nullptr;
-
-jni::jclass* rectFClass = nullptr;
-jni::jmethodID* rectFConstructorId = nullptr;
-jni::jfieldID* rectFLeftId = nullptr;
-jni::jfieldID* rectFTopId = nullptr;
-jni::jfieldID* rectFRightId = nullptr;
-jni::jfieldID* rectFBottomId = nullptr;
-
-// Offline declarations start
-
-jni::jfieldID* offlineManagerClassPtrId = nullptr;
-
-jni::jmethodID* listOnListMethodId = nullptr;
-jni::jmethodID* listOnErrorMethodId = nullptr;
-
-jni::jclass* offlineRegionClass = nullptr;
-jni::jmethodID* offlineRegionConstructorId = nullptr;
-jni::jfieldID* offlineRegionOfflineManagerId = nullptr;
-jni::jfieldID* offlineRegionIdId = nullptr;
-jni::jfieldID* offlineRegionDefinitionId = nullptr;
-jni::jfieldID* offlineRegionMetadataId = nullptr;
-jni::jfieldID* offlineRegionPtrId = nullptr;
-
-jni::jclass* offlineRegionDefinitionClass = nullptr;
-jni::jmethodID* offlineRegionDefinitionConstructorId = nullptr;
-jni::jfieldID* offlineRegionDefinitionStyleURLId = nullptr;
-jni::jfieldID* offlineRegionDefinitionBoundsId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMinZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionMaxZoomId = nullptr;
-jni::jfieldID* offlineRegionDefinitionPixelRatioId = nullptr;
-
-jni::jmethodID* createOnCreateMethodId = nullptr;
-jni::jmethodID* createOnErrorMethodId = nullptr;
-
-jni::jmethodID* updateMetadataOnUpdateMethodId = nullptr;
-jni::jmethodID* updateMetadataOnErrorMethodId = nullptr;
-
-jni::jmethodID* offlineRegionObserveronStatusChangedId = nullptr;
-jni::jmethodID* offlineRegionObserveronErrorId = nullptr;
-jni::jmethodID* offlineRegionObserveronLimitId = nullptr;
-
-jni::jclass* offlineRegionStatusClass = nullptr;
-jni::jmethodID* offlineRegionStatusConstructorId = nullptr;
-jni::jfieldID* offlineRegionStatusDownloadStateId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedResourceSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileCountId = nullptr;
-jni::jfieldID* offlineRegionStatusCompletedTileSizeId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountId = nullptr;
-jni::jfieldID* offlineRegionStatusRequiredResourceCountIsPreciseId = nullptr;
-
-jni::jclass* offlineRegionErrorClass = nullptr;
-jni::jmethodID* offlineRegionErrorConstructorId = nullptr;
-jni::jfieldID* offlineRegionErrorReasonId = nullptr;
-jni::jfieldID* offlineRegionErrorMessageId = nullptr;
-
-jni::jmethodID* offlineRegionStatusOnStatusId = nullptr;
-jni::jmethodID* offlineRegionStatusOnErrorId = nullptr;
-
-jni::jmethodID* offlineRegionDeleteOnDeleteId = nullptr;
-jni::jmethodID* offlineRegionDeleteOnErrorId = nullptr;
-
-// Offline declarations end
-
+//TODO: remove
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
assert(vm != nullptr);
assert(env != nullptr);
@@ -194,6 +67,7 @@ bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName) {
return detach;
}
+//TODO: remove
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
if (detach) {
assert(vm != nullptr);
@@ -208,1843 +82,62 @@ void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
*env = nullptr;
}
-std::string std_string_from_jstring(JNIEnv *env, jni::jstring* jstr) {
- return jni::Make<std::string>(*env, jni::String(jstr));
-}
-
-jni::jstring* std_string_to_jstring(JNIEnv *env, std::string str) {
- return jni::Make<jni::String>(*env, str).Get();
-}
-
-std::vector<std::string> std_vector_string_from_jobject(JNIEnv *env, jni::jobject* jlist) {
- std::vector<std::string> vector;
-
- jni::NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
-
- jni::NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jstring* jstr = reinterpret_cast<jni::jstring*>(jni::GetObjectArrayElement(*env, *jarray, i));
- vector.push_back(std_string_from_jstring(env, jstr));
- }
-
- return vector;
-}
-
-jni::jobject* std_vector_string_to_jobject(JNIEnv *env, std::vector<std::string> vector) {
- jni::jobject* jlist = &jni::NewObject(*env, *arrayListClass, *arrayListConstructorId);
-
- for (const auto& str : vector) {
- jni::CallMethod<jboolean>(*env, jlist, *arrayListAddId, std_string_to_jstring(env, str));
- }
-
- return jlist;
-}
-
-jni::jarray<jlong>* std_vector_uint_to_jobject(JNIEnv *env, const std::vector<uint32_t>& vector) {
- jni::jarray<jlong>& jarray = jni::NewArray<jlong>(*env, vector.size());
-
- std::vector<jlong> v;
- v.reserve(vector.size());
- std::move(vector.begin(), vector.end(), std::back_inserter(v));
-
- jni::SetArrayRegion(*env, jarray, 0, v);
-
- return &jarray;
-}
-
-static std::vector<uint8_t> metadata_from_java(JNIEnv* env, jni::jarray<jbyte>& j) {
- std::size_t length = jni::GetArrayLength(*env, j);
- std::vector<uint8_t> c;
- c.resize(length);
- jni::GetArrayRegion(*env, j, 0, length, reinterpret_cast<jbyte*>(c.data()));
- return c;
-}
-
-static jni::jarray<jbyte>* metadata_from_native(JNIEnv* env, const std::vector<uint8_t>& c) {
- std::size_t length = static_cast<std::size_t>(c.size());
- jni::jarray<jbyte>& j = jni::NewArray<jbyte>(*env, length);
- jni::SetArrayRegion(*env, j, 0, c.size(), reinterpret_cast<const jbyte*>(c.data()));
- return &j;
-}
-
-static mbgl::LatLngBounds latlngbounds_from_java(JNIEnv *env, jni::jobject* latLngBounds) {
- jdouble swLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatSouthId);
- jdouble swLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonWestId);
- jdouble neLat = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLatNorthId);
- jdouble neLon = jni::GetField<jdouble>(*env, latLngBounds, *latLngBoundsLonEastId);
- return mbgl::LatLngBounds::hull({ swLat, swLon }, { neLat, neLon });
-}
-
-static jni::jobject* latlngbounds_from_native(JNIEnv *env, mbgl::LatLngBounds bounds) {
- double northLatitude = bounds.north();
- double eastLongitude = bounds.east();
- double southLatitude = bounds.south();
- double westLongitude = bounds.west();
-
- jni::jobject* jbounds = &jni::NewObject(*env, *latLngBoundsClass, *latLngBoundsConstructorId,
- northLatitude, eastLongitude, southLatitude, westLongitude);
-
- return jbounds;
-}
-
-}
-}
-
-namespace {
-
-using namespace mbgl::android;
-using DebugOptions = mbgl::MapDebugOptions;
-
-jlong nativeCreate(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* dataPath_, jni::jstring* apkPath_, jfloat pixelRatio, jint availableProcessors, jlong totalMemory) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreate");
- cachePath = std_string_from_jstring(env, cachePath_);
- dataPath = std_string_from_jstring(env, dataPath_);
- apkPath = std_string_from_jstring(env, apkPath_);
- return reinterpret_cast<jlong>(new NativeMapView(env, jni::Unwrap(obj), pixelRatio, availableProcessors, totalMemory));
-}
-
-void nativeDestroy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroy");
- assert(nativeMapViewPtr != 0);
- delete reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-}
-
-void nativeInitializeDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeDisplay();
-}
-
-void nativeTerminateDisplay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateDisplay");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateDisplay();
-}
-
-void nativeInitializeContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeInitializeContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->initializeContext();
-}
-
-void nativeTerminateContext(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeTerminateContext");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->terminateContext();
-}
-
-void nativeCreateSurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* surface) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeCreateSurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->createSurface(ANativeWindow_fromSurface(env, jni::Unwrap(surface)));
-}
-
-void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeDestroySurface");
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->destroySurface();
-}
-
-void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->invalidate();
-}
-
-void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->render();
-}
-
-void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeViewResize");
- assert(nativeMapViewPtr != 0);
- assert(width >= 0);
- assert(height >= 0);
- assert(width <= UINT16_MAX);
- assert(height <= UINT16_MAX);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeView(width, height);
-}
-
-void nativeFramebufferResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint fbWidth, jint fbHeight) {
- mbgl::Log::Debug(mbgl::Event::JNI, "nativeFramebufferResize");
- assert(nativeMapViewPtr != 0);
- assert(fbWidth >= 0);
- assert(fbHeight >= 0);
- assert(fbWidth <= UINT16_MAX);
- assert(fbHeight <= UINT16_MAX);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->resizeFramebuffer(fbWidth, fbHeight);
-}
-
-void nativeRemoveClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeClass(std_string_from_jstring(env, clazz));
-}
-
-jboolean nativeHasClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().hasClass(std_string_from_jstring(env, clazz));
-}
-
-void nativeAddClass(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* clazz) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().addClass(std_string_from_jstring(env, clazz));
-}
-
-void nativeSetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* classes) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setClasses(std_vector_string_from_jobject(env, classes));
-}
-
-jni::jobject* nativeGetClasses(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_vector_string_to_jobject(env, nativeMapView->getMap().getClasses());
-}
-
-void nativeSetAPIBaseURL(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getFileSource().setAPIBaseURL(std_string_from_jstring(env, url));
-}
-
-void nativeSetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* url) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setStyleURL(std_string_from_jstring(env, url));
-}
-
-jni::jstring* nativeGetStyleUrl(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr){
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getMap().getStyleURL());
-}
-
-void nativeSetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* newStyleJson) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setStyleJSON(std_string_from_jstring(env, newStyleJson));
-}
-
-jni::jstring* nativeGetStyleJson(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getMap().getStyleJSON());
-}
-
-void nativeSetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* accessToken) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getFileSource().setAccessToken(std_string_from_jstring(env, accessToken));
-}
-
-jni::jstring* nativeGetAccessToken(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return std_string_to_jstring(env, nativeMapView->getFileSource().getAccessToken());
-}
-
-void nativeCancelTransitions(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().cancelTransitions();
-}
-
-void nativeSetGestureInProgress(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean inProgress) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setGestureInProgress(inProgress);
-}
-
-void nativeMoveBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble dx, jdouble dy,
- jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().moveBy({dx, dy}, mbgl::Milliseconds(duration));
-}
-
-void nativeSetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setLatLng(mbgl::LatLng(latitude, longitude), nativeMapView->getInsets(), mbgl::Duration(duration));
-}
-
-jni::jobject* nativeGetLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets());
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jdoubleArray nativeGetCameraValues(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().getLatLng(nativeMapView->getInsets());
- jdoubleArray output = env->NewDoubleArray(5);
- jsize start = 0;
- jsize leng = 5;
- jdouble buf[5];
- buf[0] = latLng.latitude;
- buf[1] = latLng.longitude;
- buf[2] = -nativeMapView->getMap().getBearing();
- buf[3] = nativeMapView->getMap().getPitch();
- buf[4] = nativeMapView->getMap().getZoom();
- env->SetDoubleArrayRegion(output, start, leng, buf);
-
- if (output == nullptr) {
- env->ExceptionDescribe();
- return nullptr;
- }
-
- return output;
-}
-
-void nativeResetPosition(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetPosition();
-}
-
-jdouble nativeGetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getPitch();
-}
-
-void nativeSetPitch(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble pitch, jlong milliseconds) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::Duration duration((mbgl::Milliseconds(milliseconds)));
- nativeMapView->getMap().setPitch(pitch, duration);
-}
-
-void nativeScaleBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble ds, jdouble cx,
- jdouble cy, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().scaleBy(ds, center, mbgl::Milliseconds(duration));
-}
-
-void nativeSetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble scale,
- jdouble cx, jdouble cy, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().setScale(scale, center, mbgl::Milliseconds(duration));
-}
-
-jdouble nativeGetScale(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getScale();
-}
-
-void nativeSetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setZoom(zoom, mbgl::Milliseconds(duration));
-}
-
-jdouble nativeGetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getZoom();
-}
-
-void nativeResetZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetZoom();
-}
-
-void nativeSetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMinZoom(zoom);
-}
-
-jdouble nativeGetMinZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMinZoom();
-}
-
-void nativeSetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().setMaxZoom(zoom);
-}
-
-jdouble nativeGetMaxZoom(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMaxZoom();
-}
-
-void nativeRotateBy(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble sx,
- jdouble sy, jdouble ex, jdouble ey, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate first(sx, sy);
- mbgl::ScreenCoordinate second(ex, ey);
- nativeMapView->getMap().rotateBy(first, second, mbgl::Milliseconds(duration));
-}
-
-void nativeSetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees,
- jlong milliseconds) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::Duration duration((mbgl::Milliseconds(milliseconds)));
- nativeMapView->getMap().setBearing(degrees, duration);
-}
-
-void nativeSetBearingXY(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble degrees,
- jdouble cx, jdouble cy) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate center(cx, cy);
- nativeMapView->getMap().setBearing(degrees, center);
-}
-
-jdouble nativeGetBearing(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getBearing();
-}
-
-void nativeResetNorth(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().resetNorth();
-}
-
-void nativeUpdateMarker(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong markerId, jdouble lat, jdouble lon, jni::jstring* jid) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- if (markerId == -1) {
- return;
- }
- std::string iconId = std_string_from_jstring(env, jid);
- // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
- nativeMapView->getMap().updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point<double>(lon, lat), iconId });
-}
-
-jni::jarray<jlong>* nativeAddMarkers(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* marker = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* position = jni::GetField<jni::jobject*>(*env, marker, *markerPositionId);
- jni::jobject* icon = jni::GetField<jni::jobject*>(*env, marker, *markerIconId);
- jni::jstring* jid = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, icon, *iconIdId));
-
- jdouble latitude = jni::GetField<jdouble>(*env, position, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, position, *latLngLongitudeId);
-
- ids.push_back(nativeMapView->getMap().addAnnotation(mbgl::SymbolAnnotation {
- mbgl::Point<double>(longitude, latitude),
- std_string_from_jstring(env, jid)
- }));
-
- jni::DeleteLocalRef(*env, position);
- jni::DeleteLocalRef(*env, jid);
- jni::DeleteLocalRef(*env, icon);
- jni::DeleteLocalRef(*env, marker);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-static mbgl::Color toColor(jint color) {
- float r = (color >> 16) & 0xFF;
- float g = (color >> 8) & 0xFF;
- float b = (color) & 0xFF;
- float a = (color >> 24) & 0xFF;
- return { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f };
-}
-
-template <class Geometry>
-Geometry toGeometry(JNIEnv *env, jni::jobject* jlist) {
- NullCheck(*env, jlist);
- jni::jarray<jni::jobject>* jarray =
- reinterpret_cast<jni::jarray<jni::jobject>*>(jni::CallMethod<jni::jobject*>(*env, jlist, *listToArrayId));
- NullCheck(*env, jarray);
-
- std::size_t size = jni::GetArrayLength(*env, *jarray);
-
- Geometry geometry;
- geometry.reserve(size);
-
- for (std::size_t i = 0; i < size; i++) {
- jni::jobject* latLng = reinterpret_cast<jni::jobject*>(jni::GetObjectArrayElement(*env, *jarray, i));
- NullCheck(*env, latLng);
-
- geometry.push_back(mbgl::Point<double>(
- jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId),
- jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId)));
-
- jni::DeleteLocalRef(*env, latLng);
- }
-
- jni::DeleteLocalRef(*env, jarray);
- jni::DeleteLocalRef(*env, jlist);
-
- return geometry;
-}
-
-jni::jarray<jlong>* nativeAddPolylines(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* polyline = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
-
- jni::DeleteLocalRef(*env, polyline);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-jni::jarray<jlong>* nativeAddPolygons(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jni::jobject>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
-
- mbgl::AnnotationIDs ids;
- ids.reserve(len);
-
- for (std::size_t i = 0; i < len; i++) {
- jni::jobject* polygon = jni::GetObjectArrayElement(*env, *jarray, i);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
- ids.push_back(nativeMapView->getMap().addAnnotation(annotation));
-
- jni::DeleteLocalRef(*env, polygon);
- }
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-void nativeUpdatePolygon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polygonId, jni::jobject* polygon) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polygon, *polygonPointsId);
-
- mbgl::FillAnnotation annotation { mbgl::Polygon<double> { toGeometry<mbgl::LinearRing<double>>(env, points) } };
- annotation.opacity = { jni::GetField<jfloat>(*env, polygon, *polygonAlphaId) };
- annotation.outlineColor = { toColor(jni::GetField<jint>(*env, polygon, *polygonStrokeColorId)) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polygon, *polygonFillColorId)) };
- nativeMapView->getMap().updateAnnotation(polygonId, annotation);
-}
-
-void nativeUpdatePolyline(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong polylineId, jni::jobject* polyline) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- jni::jobject* points = jni::GetField<jni::jobject*>(*env, polyline, *polylinePointsId);
-
- mbgl::LineAnnotation annotation { toGeometry<mbgl::LineString<double>>(env, points) };
- annotation.opacity = { jni::GetField<jfloat>(*env, polyline, *polylineAlphaId) };
- annotation.color = { toColor(jni::GetField<jint>(*env, polyline, *polylineColorId)) };
- annotation.width = { jni::GetField<jfloat>(*env, polyline, *polylineWidthId) };
- nativeMapView->getMap().updateAnnotation(polylineId, annotation);
-}
-
-void nativeRemoveAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jarray<jlong>* jarray) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- NullCheck(*env, jarray);
- std::size_t len = jni::GetArrayLength(*env, *jarray);
- auto elements = jni::GetArrayElements(*env, *jarray);
- jlong* jids = std::get<0>(elements).get();
-
- for (std::size_t i = 0; i < len; i++) {
- if(jids[i] == -1L)
- continue;
- nativeMapView->getMap().removeAnnotation(jids[i]);
- }
-}
-
-jni::jarray<jlong>* nativeQueryPointAnnotations(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jobject* rect) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Conversion
- jfloat left = jni::GetField<jfloat>(*env, rect, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, rect, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, rect, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*env, rect, *rectFBottomId);
- mbgl::ScreenBox box = {
- { left, top },
- { right, bottom },
- };
-
- // Assume only points for now
- mbgl::AnnotationIDs ids = nativeMapView->getMap().queryPointAnnotations(box);
-
- return std_vector_uint_to_jobject(env, ids);
-}
-
-void nativeAddAnnotationIcon(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jstring* symbol, jint width, jint height, jfloat scale, jni::jarray<jbyte>* jpixels) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const std::string symbolName = std_string_from_jstring(env, symbol);
-
- NullCheck(*env, jpixels);
- std::size_t size = jni::GetArrayLength(*env, *jpixels);
- mbgl::PremultipliedImage premultipliedImage(
- { static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- auto iconImage = std::make_shared<mbgl::SpriteImage>(
- std::move(premultipliedImage),
- float(scale));
-
- nativeMapView->getMap().addAnnotationIcon(symbolName, iconImage);
-}
-
-void nativeSetVisibleCoordinateBounds(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr,
- jni::jarray<jni::jobject>* coordinates, jni::jobject* padding, jdouble direction, jlong duration) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- jfloat left = jni::GetField<jfloat>(*env, padding, *rectFLeftId);
- jfloat right = jni::GetField<jfloat>(*env, padding, *rectFRightId);
- jfloat top = jni::GetField<jfloat>(*env, padding, *rectFTopId);
- jfloat bottom = jni::GetField<jfloat>(*env, padding, *rectFBottomId);
-
- NullCheck(*env, coordinates);
- std::size_t count = jni::GetArrayLength(*env, *coordinates);
-
- mbgl::EdgeInsets mbglInsets = {top, left, bottom, right};
- std::vector<mbgl::LatLng> latLngs;
- latLngs.reserve(count);
-
- for (std::size_t i = 0; i < count; i++) {
- jni::jobject* latLng = jni::GetObjectArrayElement(*env, *coordinates, i);
- jdouble latitude = jni::GetField<jdouble>(*env, latLng, *latLngLatitudeId);
- jdouble longitude = jni::GetField<jdouble>(*env, latLng, *latLngLongitudeId);
- latLngs.push_back(mbgl::LatLng(latitude, longitude));
- }
-
- mbgl::CameraOptions cameraOptions = nativeMapView->getMap().cameraForLatLngs(latLngs, mbglInsets);
- if (direction >= 0) {
- // convert from degrees to radians
- cameraOptions.angle = (-direction * M_PI) / 180;
- }
- mbgl::AnimationOptions animationOptions;
- if (duration > 0) {
- animationOptions.duration.emplace(mbgl::Milliseconds(duration));
- // equivalent to kCAMediaTimingFunctionDefault in iOS
- animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 });
- }
-
- nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
-}
-
-jni::jarray<jni::jobject>* nativeQueryRenderedFeaturesForPoint(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat x, jni::jfloat y, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- point<double> point = {x, y};
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(point, layers));
-}
-
-jni::jarray<jni::jobject>* nativeQueryRenderedFeaturesForBox(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::jarray<jni::jobject>* layerIds) {
- using namespace mbgl::android::conversion;
- using namespace mapbox::geometry;
-
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::optional<std::vector<std::string>> layers;
- if (layerIds != nullptr && jni::GetArrayLength(*env, *layerIds) > 0) {
- layers = toVector(*env, *layerIds);
- }
- box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
-
- return *convert<jni::jarray<jni::jobject>*, std::vector<mbgl::Feature>>(*env, nativeMapView->getMap().queryRenderedFeatures(box, layers));
-}
-
-void nativeOnLowMemory(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().onLowMemory();
-}
-
-void nativeSetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean debug) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision
- : DebugOptions::NoDebug;
- nativeMapView->getMap().setDebug(debugOptions);
- nativeMapView->enableFps(debug);
-}
-
-void nativeToggleDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().cycleDebugOptions();
- nativeMapView->enableFps(nativeMapView->getMap().getDebug() != DebugOptions::NoDebug);
-}
-
-jboolean nativeGetDebug(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getDebug() != DebugOptions::NoDebug;
-}
-
-jboolean nativeIsFullyLoaded(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().isFullyLoaded();
-}
-
-void nativeSetReachability(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jboolean status) {
- assert(nativeMapViewPtr != 0);
- if (status) {
- mbgl::NetworkStatus::Reachable();
- }
-}
-
-jdouble nativeGetMetersPerPixelAtLatitude(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble lat, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getMetersPerPixelAtLatitude(lat, zoom);
-}
-
-jni::jobject* nativeProjectedMetersForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ProjectedMeters projectedMeters = nativeMapView->getMap().projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
- return &jni::NewObject(*env, *projectedMetersClass, *projectedMetersConstructorId, projectedMeters.northing, projectedMeters.easting);
-}
-
-jni::jobject* nativeLatLngForProjectedMeters(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble northing, jdouble easting) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jni::jobject* nativePixelForLatLng(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble latitude, jdouble longitude) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::ScreenCoordinate pixel = nativeMapView->getMap().pixelForLatLng(mbgl::LatLng(latitude, longitude));
- return &jni::NewObject(*env, *pointFClass, *pointFConstructorId, static_cast<jfloat>(pixel.x), static_cast<jfloat>(pixel.y));
-}
-
-jni::jobject* nativeLatLngForPixel(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jfloat x, jfloat y) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::LatLng latLng = nativeMapView->getMap().latLngForPixel(mbgl::ScreenCoordinate(x, y));
- return &jni::NewObject(*env, *latLngClass, *latLngConstructorId, latLng.latitude, latLng.longitude);
-}
-
-jdouble nativeGetTopOffsetPixelsForAnnotationSymbol(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* symbolName) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- return nativeMapView->getMap().getTopOffsetPixelsForAnnotationIcon(std_string_from_jstring(env, symbolName));
-}
-
-void nativeJumpTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jdouble pitch, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions options;
- if (angle != -1) {
- options.angle = (-angle * M_PI) / 180;
- }
- options.center = mbgl::LatLng(latitude, longitude);
- options.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- options.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- options.zoom = zoom;
- }
-
- nativeMapView->getMap().jumpTo(options);
-}
-
-void nativeEaseTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom, jboolean easing) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions cameraOptions;
- if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180;
- }
- cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- cameraOptions.zoom = zoom;
- }
- mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
-
- if (!easing) {
- // add a linear interpolator instead of easing
- animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
- }
-
- nativeMapView->getMap().easeTo(cameraOptions, animationOptions);
-}
-
-void nativeSetContentPadding(JNIEnv *env, jni::jobject* obj,long nativeMapViewPtr, double top, double left, double bottom, double right) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->setInsets({top, left, bottom, right});
-}
-
-void nativeFlyTo(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jdouble angle, jdouble latitude, jdouble longitude, jlong duration, jdouble pitch, jdouble zoom) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- mbgl::CameraOptions cameraOptions;
- if (angle != -1) {
- cameraOptions.angle = (-angle * M_PI) / 180 ;
- }
- cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = nativeMapView->getInsets();
- if (pitch != -1) {
- cameraOptions.pitch = pitch * M_PI / 180;
- }
- if (zoom != -1) {
- cameraOptions.zoom = zoom;
- }
- mbgl::AnimationOptions animationOptions;
- animationOptions.duration.emplace(mbgl::Duration(duration));
-
- nativeMapView->getMap().flyTo(cameraOptions, animationOptions);
-}
-
-jlong nativeGetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- return transitionOptions.duration.value_or(mbgl::Duration::zero()).count();
-}
-
-void nativeSetTransitionDuration(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong duration) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
- nativeMapView->getMap().setTransitionOptions(transitionOptions);
-}
-
-jlong nativeGetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- const auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- return transitionOptions.delay.value_or(mbgl::Duration::zero()).count();
-}
-
-void nativeSetTransitionDelay(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong delay) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- auto transitionOptions = nativeMapView->getMap().getTransitionOptions();
- transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(delay));
- nativeMapView->getMap().setTransitionOptions(transitionOptions);
-}
-
-jni::jobject* nativeGetLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* layerId) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- //Get the native map peer
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- //Find the layer
- mbgl::style::Layer* coreLayer = nativeMapView->getMap().getLayer(std_string_from_jstring(env, layerId));
- if (!coreLayer) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
- return jni::Object<Layer>();
- }
-
- //Create and return the layer's native peer
- return createJavaLayerPeer(*env, nativeMapView->getMap(), *coreLayer);
-}
-
-void nativeAddLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong nativeLayerPtr, jni::jstring* before) {
- assert(nativeMapViewPtr != 0);
- assert(nativeLayerPtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
- try {
- layer->addToMap(nativeMapView->getMap(), before ? mbgl::optional<std::string>(std_string_from_jstring(env, before)) : mbgl::optional<std::string>());
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
- }
-}
-
-/**
- * Remove by layer id. Ownership is not transferred back
- */
-void nativeRemoveLayerById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- try {
- nativeMapView->getMap().removeLayer(std_string_from_jstring(env, id));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what());
- }
-}
-
-/**
- * Remove with wrapper object id. Ownership is transferred back to the wrapper
- */
-void nativeRemoveLayer(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong layerPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
- try {
- std::unique_ptr<mbgl::style::Layer> coreLayer = nativeMapView->getMap().removeLayer(layer->get().getID());
- layer->setLayer(std::move(coreLayer));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/layers/NoSuchLayerException"), error.what());
- }
-}
-
-
-jni::jobject* nativeGetSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jstring* sourceId) {
- assert(env);
- assert(nativeMapViewPtr != 0);
-
- //Get the native map peer
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- //Find the source
- mbgl::style::Source* coreSource = nativeMapView->getMap().getSource(std_string_from_jstring(env, sourceId));
- if (!coreSource) {
- mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
- return jni::Object<Source>();
- }
-
- //Create and return the source's native peer
- return createJavaSourcePeer(*env, nativeMapView->getMap(), *coreSource);
-}
-
-void nativeAddSource(JNIEnv *env, jni::jobject* obj, jni::jlong nativeMapViewPtr, jni::jlong nativeSourcePtr) {
- assert(nativeMapViewPtr != 0);
- assert(nativeSourcePtr != 0);
-
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- Source *source = reinterpret_cast<Source *>(nativeSourcePtr);
- try {
- source->addToMap(nativeMapView->getMap());
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what());
- }
-}
-
-void nativeRemoveSourceById(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* id) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- try {
- nativeMapView->getMap().removeSource(std_string_from_jstring(env, id));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what());
- }
-}
-
-void nativeRemoveSource(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jlong sourcePtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
- try {
- std::unique_ptr<mbgl::style::Source> coreSource = nativeMapView->getMap().removeSource(source->get().getID());
- source->setSource(std::move(coreSource));
- } catch (const std::runtime_error& error) {
- jni::ThrowNew(*env, jni::FindClass(*env, "com/mapbox/mapboxsdk/style/sources/NoSuchSourceException"), error.what());
- }
-}
-
-void nativeAddImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name, jni::jint width, jni::jint height, jni::jfloat pixelRatio, jni::jarray<jbyte>* data) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
-
- // Create Pre-multiplied image from byte[]
- NullCheck(*env, data);
- std::size_t size = jni::GetArrayLength(*env, *data);
- mbgl::PremultipliedImage premultipliedImage(
- { static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-
- if (premultipliedImage.bytes() != uint32_t(size)) {
- throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
- }
-
- jni::GetArrayRegion(*env, *data, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
-
- //Wrap in a SpriteImage with the correct pixel ratio
- auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(pixelRatio));
-
- nativeMapView->getMap().addImage(std_string_from_jstring(env, name), std::move(spriteImage));
-}
-
-void nativeRemoveImage(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jni::jstring* name) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->getMap().removeImage(std_string_from_jstring(env, name));
-}
-
-void nativeScheduleTakeSnapshot(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
- assert(nativeMapViewPtr != 0);
- NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
- nativeMapView->scheduleTakeSnapshot();
-}
-
-// Offline calls begin
-
-jlong createDefaultFileSource(JNIEnv *env, jni::jobject* obj, jni::jstring* cachePath_, jni::jstring* assetRoot_, jlong maximumCacheSize) {
- std::string cachePath = std_string_from_jstring(env, cachePath_);
- std::string assetRoot = std_string_from_jstring(env, assetRoot_);
- mbgl::DefaultFileSource *defaultFileSource = new mbgl::DefaultFileSource(cachePath, assetRoot, maximumCacheSize);
- jlong defaultFileSourcePtr = reinterpret_cast<jlong>(defaultFileSource);
- return defaultFileSourcePtr;
-}
-
-void setAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jstring* accessToken_) {
- assert(defaultFileSourcePtr != 0);
- std::string accessToken = std_string_from_jstring(env, accessToken_);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setAccessToken(accessToken);
-}
-
-jni::jstring* getAccessToken(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr) {
- assert(defaultFileSourcePtr != 0);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- std::string accessToken = defaultFileSource->getAccessToken();
- return std_string_to_jstring(env, accessToken);
-}
-
-void listOfflineRegions(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* listCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, listCallback);
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- listCallback = jni::NewGlobalRef(*env, listCallback).release();
-
- // Launch listCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->listOfflineRegions([obj, defaultFileSourcePtr, listCallback](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, listCallback, *listOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (regions) {
- // Build jni::jarray<jni::jobject>*
- std::size_t index = 0;
- jni::jarray<jni::jobject>* jregions = &jni::NewObjectArray(*env2, regions->size(), *offlineRegionClass, NULL);
- for (auto& region : *regions) {
- // Create a new local reference frame (capacity 2 for the NewObject allocations below)
- // to avoid a local reference table overflow (#5629)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 2);
-
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region.getID());
-
- // Definition object
- mbgl::OfflineTilePyramidRegionDefinition definition = region.getDefinition();
- jni::jobject* jdefinition = &jni::NewObject(*env2, *offlineRegionDefinitionClass, *offlineRegionDefinitionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionStyleURLId, std_string_to_jstring(env2, definition.styleURL));
- jni::SetField<jni::jobject*>(*env2, jdefinition, *offlineRegionDefinitionBoundsId, latlngbounds_from_native(env2, definition.bounds));
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMinZoomId, definition.minZoom);
- jni::SetField<jdouble>(*env2, jdefinition, *offlineRegionDefinitionMaxZoomId, definition.maxZoom);
- jni::SetField<jfloat>(*env2, jdefinition, *offlineRegionDefinitionPixelRatioId, definition.pixelRatio);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionDefinitionId, jdefinition);
-
- // Metadata object
- jni::jarray<jbyte>* metadata = metadata_from_native(env2, region.getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, metadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(region))));
-
- jni::SetObjectArrayElement(*env2, *jregions, index, jregion);
- index++;
- }
-
- // Trigger callback
- jni::CallMethod<void>(*env2, listCallback, *listOnListMethodId, jregions);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(listCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void createOfflineRegion(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jni::jobject* definition_, jni::jarray<jbyte>* metadata_, jni::jobject* createCallback) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- NullCheck(*env, createCallback);
-
- // Definition fields
- jni::jstring* jStyleURL = reinterpret_cast<jni::jstring*>(jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionStyleURLId));
- std::string styleURL = std_string_from_jstring(env, jStyleURL);
- jni::jobject* jBounds = jni::GetField<jni::jobject*>(*env, definition_, *offlineRegionDefinitionBoundsId);
- jdouble jMinZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMinZoomId);
- jdouble jMaxZoom = jni::GetField<jdouble>(*env, definition_, *offlineRegionDefinitionMaxZoomId);
- jfloat jPixelRatio = jni::GetField<jfloat>(*env, definition_, *offlineRegionDefinitionPixelRatioId);
-
- // Convert bounds fields to native
- mbgl::LatLngBounds bounds = latlngbounds_from_java(env, jBounds);
-
- // Definition
- mbgl::OfflineTilePyramidRegionDefinition definition(styleURL, bounds, jMinZoom, jMaxZoom, jPixelRatio);
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- obj = jni::NewGlobalRef(*env, obj).release();
- createCallback = jni::NewGlobalRef(*env, createCallback).release();
-
- // Launch createCallback
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->createOfflineRegion(definition, metadata, [obj, defaultFileSourcePtr, createCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, createCallback, *createOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (region) {
- // Build the Region object
- jni::jobject* jregion = &jni::NewObject(*env2, *offlineRegionClass, *offlineRegionConstructorId);
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionOfflineManagerId, obj);
- jni::SetField<jlong>(*env2, jregion, *offlineRegionIdId, region->getID());
-
- // Metadata object
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, region->getMetadata());
- jni::SetField<jni::jobject*>(*env2, jregion, *offlineRegionMetadataId, jmetadata);
-
- // Moves the region on the stack into a heap-allocated one
- jni::SetField<jlong>(*env2, jregion, *offlineRegionPtrId,
- reinterpret_cast<jlong>(new mbgl::OfflineRegion(std::move(*region))));
-
- // Invoke Java callback
- jni::CallMethod<void>(*env2, createCallback, *createOnCreateMethodId, jregion);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(obj));
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(createCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void setOfflineMapboxTileCountLimit(JNIEnv *env, jni::jobject* obj, jlong defaultFileSourcePtr, jlong limit) {
- // Checks
- assert(defaultFileSourcePtr != 0);
- assert(limit > 0);
-
- // Set limit
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
- defaultFileSource->setOfflineMapboxTileCountLimit(limit);
-}
-
-mbgl::OfflineRegion* getOfflineRegionPeer(JNIEnv *env, jni::jobject* offlineRegion_) {
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- jni::ThrowNew(*env, jni::FindClass(*env, "java/lang/IllegalStateException"),
- "Use of OfflineRegion after OfflineRegion.delete");
- }
- return reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
-}
-
-void destroyOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_) {
- // Offline region
- jlong offlineRegionPtr = jni::GetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId);
- if (!offlineRegionPtr) {
- return; // Already deleted
- }
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Release the observer and delete the region
- mbgl::OfflineRegion *offlineRegion = reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr);
- defaultFileSource->setOfflineRegionObserver(*offlineRegion, nullptr);
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- delete offlineRegion;
-}
-
-void setOfflineRegionObserver(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* observerCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Define the observer
- class Observer : public mbgl::OfflineRegionObserver {
- public:
- Observer(jni::UniqueGlobalRef<jni::jobject>&& observerCallback_)
- : observerCallback(std::move(observerCallback_)) {
- }
-
- ~Observer() override {
- mbgl::Log::Debug(mbgl::Event::JNI, "~Observer()");
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- jni::DeleteGlobalRef(*env2, std::move(observerCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void statusChanged(mbgl::OfflineRegionStatus status) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Conver to jint
- jint downloadState;
- switch(status.downloadState) {
- case mbgl::OfflineRegionDownloadState::Inactive:
- downloadState = 0;
- break;
- case mbgl::OfflineRegionDownloadState::Active:
- downloadState = 1;
- break;
- }
-
- // Create a new local reference frame (capacity 1 for the NewObject allocation below)
- // to avoid a local reference table overflow (#4706)
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 1);
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status.completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status.completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileCountId, status.completedTileCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedTileSizeId, status.completedTileSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status.requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status.requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronStatusChangedId, jstatus);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void responseError(mbgl::Response::Error error) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Handle the value of reason independently of the underlying int value
- std::string errorReason;
- switch(error.reason) {
- case mbgl::Response::Error::Reason::Success:
- errorReason = "REASON_SUCCESS";
- break;
- case mbgl::Response::Error::Reason::NotFound:
- errorReason = "REASON_NOT_FOUND";
- break;
- case mbgl::Response::Error::Reason::Server:
- errorReason = "REASON_SERVER";
- break;
- case mbgl::Response::Error::Reason::Connection:
- errorReason = "REASON_CONNECTION";
- break;
- case mbgl::Response::Error::Reason::RateLimit:
- errorReason = "REASON_RATE_LIMIT";
- break;
- case mbgl::Response::Error::Reason::Other:
- errorReason = "REASON_OTHER";
- break;
- }
-
- // Error object
- jni::UniqueLocalFrame frame = jni::PushLocalFrame(*env2, 3);
- jni::jobject* jerror = &jni::NewObject(*env2, *offlineRegionErrorClass, *offlineRegionErrorConstructorId);
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorReasonId, std_string_to_jstring(env2, errorReason));
- jni::SetField<jni::jobject*>(*env2, jerror, *offlineRegionErrorMessageId, std_string_to_jstring(env2, error.message));
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronErrorId, jerror);
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- void mapboxTileCountLimitExceeded(uint64_t limit) override {
- // Env
- JNIEnv* env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
-
- // Send limit
- jni::CallMethod<void>(*env2, observerCallback.get(), *offlineRegionObserveronLimitId, jlong(limit));
-
- // Detach when we're done
- detach_jni_thread(theJVM, &env2, renderDetach);
- }
-
- jni::UniqueGlobalRef<jni::jobject> observerCallback;
- };
-
- // Set the observer
- defaultFileSource->setOfflineRegionObserver(*offlineRegion,
- std::make_unique<Observer>(jni::NewGlobalRef(*env, observerCallback)));
-}
-
-void setOfflineRegionDownloadState(JNIEnv *env, jni::jobject* offlineRegion_, jint offlineRegionDownloadState) {
- // State
- mbgl::OfflineRegionDownloadState state;
- if (offlineRegionDownloadState == 0) {
- state = mbgl::OfflineRegionDownloadState::Inactive;
- } else if (offlineRegionDownloadState == 1) {
- state = mbgl::OfflineRegionDownloadState::Active;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
- return;
- }
-
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Set new state
- defaultFileSource->setOfflineRegionDownloadState(*offlineRegion, state);
-}
-
-void getOfflineRegionStatus(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* statusCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- statusCallback = jni::NewGlobalRef(*env, statusCallback).release();
-
- // Set new state
- defaultFileSource->getOfflineRegionStatus(*offlineRegion, [statusCallback](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnErrorId, std_string_to_jstring(env2, message));
- } else if (status) {
- // Conver to jint
- jint downloadState = -1;
- if (status->downloadState == mbgl::OfflineRegionDownloadState::Inactive) {
- downloadState = 0;
- } else if (status->downloadState == mbgl::OfflineRegionDownloadState::Active) {
- downloadState = 1;
- } else {
- mbgl::Log::Error(mbgl::Event::JNI, "Unsupported OfflineRegionDownloadState value.");
- return;
- }
-
- // Stats object
- jni::jobject* jstatus = &jni::NewObject(*env2, *offlineRegionStatusClass, *offlineRegionStatusConstructorId);
- jni::SetField<jint>(*env2, jstatus, *offlineRegionStatusDownloadStateId, downloadState);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceCountId, status->completedResourceCount);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusCompletedResourceSizeId, status->completedResourceSize);
- jni::SetField<jlong>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountId, status->requiredResourceCount);
- jni::SetField<jboolean>(*env2, jstatus, *offlineRegionStatusRequiredResourceCountIsPreciseId, status->requiredResourceCountIsPrecise);
- jni::CallMethod<void>(*env2, statusCallback, *offlineRegionStatusOnStatusId, jstatus);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(statusCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void deleteOfflineRegion(JNIEnv *env, jni::jobject* offlineRegion_, jni::jobject* deleteCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Makes sure the callback doesn't get GC'ed
- deleteCallback = jni::NewGlobalRef(*env, deleteCallback).release();
-
- // Set new state
- jni::SetField<jlong>(*env, offlineRegion_, *offlineRegionPtrId, 0);
- defaultFileSource->deleteOfflineRegion(std::move(*offlineRegion), [deleteCallback](std::exception_ptr error) mutable {
-
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnErrorId, std_string_to_jstring(env2, message));
- } else {
- jni::CallMethod<void>(*env2, deleteCallback, *offlineRegionDeleteOnDeleteId);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(deleteCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-void updateOfflineRegionMetadata(JNIEnv *env, jni::jobject* offlineRegion_, jni::jarray<jbyte>* metadata_, jni::jobject* updateCallback) {
- // Offline region
- mbgl::OfflineRegion* offlineRegion = getOfflineRegionPeer(env, offlineRegion_);
-
- // File source
- jni::jobject* jmanager = jni::GetField<jni::jobject*>(*env, offlineRegion_, *offlineRegionOfflineManagerId);
- jlong defaultFileSourcePtr = jni::GetField<jlong>(*env, jmanager, *offlineManagerClassPtrId);
- mbgl::DefaultFileSource *defaultFileSource = reinterpret_cast<mbgl::DefaultFileSource *>(defaultFileSourcePtr);
-
- // Id conversion
- int64_t id = offlineRegion->getID();
-
- // Metadata
- mbgl::OfflineRegionMetadata metadata;
- if (metadata_ != nullptr) {
- metadata = metadata_from_java(env, *metadata_);
- }
-
- // Makes sure the objects don't get GC'ed
- updateCallback = jni::NewGlobalRef(*env, updateCallback).release();
-
- // Launch updateCallback
- defaultFileSource->updateOfflineMetadata(id, metadata, [updateCallback] (std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
- // Reattach, the callback comes from a different thread
- JNIEnv *env2;
- jboolean renderDetach = attach_jni_thread(theJVM, &env2, "Offline Thread");
- if (renderDetach) {
- mbgl::Log::Debug(mbgl::Event::JNI, "Attached.");
- }
-
- if (error) {
- std::string message = mbgl::util::toString(error);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnErrorMethodId, std_string_to_jstring(env2, message));
- } else if (data) {
- jni::jarray<jbyte>* jmetadata = metadata_from_native(env2, *data);
- jni::CallMethod<void>(*env2, updateCallback, *updateMetadataOnUpdateMethodId, jmetadata);
- }
-
- // Delete global refs and detach when we're done
- jni::DeleteGlobalRef(*env2, jni::UniqueGlobalRef<jni::jobject>(updateCallback));
- detach_jni_thread(theJVM, &env2, renderDetach);
- });
-}
-
-// Offline calls end
-
-} // anonymous
-
-namespace mbgl {
-namespace android {
-
void registerNatives(JavaVM *vm) {
theJVM = vm;
jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+ // For the DefaultFileSource
static mbgl::util::RunLoop mainRunLoop;
+ FileSource::registerNative(env);
- mbgl::android::RegisterNativeHTTPRequest(env);
-
+ // Basic types
java::registerNatives(env);
- registerNativeLayers(env);
- registerNativeSources(env);
- ConnectivityListener::registerNative(env);
-
- latLngClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLng");
- latLngClass = jni::NewGlobalRef(env, latLngClass).release();
- latLngConstructorId = &jni::GetMethodID(env, *latLngClass, "<init>", "(DD)V");
- latLngLatitudeId = &jni::GetFieldID(env, *latLngClass, "latitude", "D");
- latLngLongitudeId = &jni::GetFieldID(env, *latLngClass, "longitude", "D");
-
- latLngBoundsClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/LatLngBounds");
- latLngBoundsClass = jni::NewGlobalRef(env, latLngBoundsClass).release();
- latLngBoundsConstructorId = &jni::GetMethodID(env, *latLngBoundsClass, "<init>", "(DDDD)V");
- latLngBoundsLatNorthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatNorth", "D");
- latLngBoundsLatSouthId = &jni::GetFieldID(env, *latLngBoundsClass, "mLatSouth", "D");
- latLngBoundsLonEastId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonEast", "D");
- latLngBoundsLonWestId = &jni::GetFieldID(env, *latLngBoundsClass, "mLonWest", "D");
-
- iconClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Icon");
- iconClass = jni::NewGlobalRef(env, iconClass).release();
- iconIdId = &jni::GetFieldID(env, *iconClass, "mId", "Ljava/lang/String;");
-
- markerClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Marker");
- markerClass = jni::NewGlobalRef(env, markerClass).release();
- markerPositionId = &jni::GetFieldID(env, *markerClass, "position", "Lcom/mapbox/mapboxsdk/geometry/LatLng;");
- markerIconId = &jni::GetFieldID(env, *markerClass, "icon", "Lcom/mapbox/mapboxsdk/annotations/Icon;");
- markerIdId = &jni::GetFieldID(env, *markerClass, "id", "J");
-
- polylineClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polyline");
- polylineClass = jni::NewGlobalRef(env, polylineClass).release();
- polylineAlphaId = &jni::GetFieldID(env, *polylineClass, "alpha", "F");
- polylineColorId = &jni::GetFieldID(env, *polylineClass, "color", "I");
- polylineWidthId = &jni::GetFieldID(env, *polylineClass, "width", "F");
- polylinePointsId = &jni::GetFieldID(env, *polylineClass, "points", "Ljava/util/List;");
-
- polygonClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/annotations/Polygon");
- polygonClass = jni::NewGlobalRef(env, polygonClass).release();
- polygonAlphaId = &jni::GetFieldID(env, *polygonClass, "alpha", "F");
- polygonFillColorId = &jni::GetFieldID(env, *polygonClass, "fillColor", "I");
- polygonStrokeColorId = &jni::GetFieldID(env, *polygonClass, "strokeColor", "I");
- polygonPointsId = &jni::GetFieldID(env, *polygonClass, "points", "Ljava/util/List;");
-
- jni::jclass* listClass = &jni::FindClass(env, "java/util/List");
- listToArrayId = &jni::GetMethodID(env, *listClass, "toArray", "()[Ljava/lang/Object;");
-
- arrayListClass = &jni::FindClass(env, "java/util/ArrayList");
- arrayListClass = jni::NewGlobalRef(env, arrayListClass).release();
- arrayListConstructorId = &jni::GetMethodID(env, *arrayListClass, "<init>", "()V");
- arrayListAddId = &jni::GetMethodID(env, *arrayListClass, "add", "(Ljava/lang/Object;)Z");
-
- projectedMetersClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/geometry/ProjectedMeters");
- projectedMetersClass = jni::NewGlobalRef(env, projectedMetersClass).release();
- projectedMetersConstructorId = &jni::GetMethodID(env, *projectedMetersClass, "<init>", "(DD)V");
- projectedMetersNorthingId = &jni::GetFieldID(env, *projectedMetersClass, "northing", "D");
- projectedMetersEastingId = &jni::GetFieldID(env, *projectedMetersClass, "easting", "D");
-
- pointFClass = &jni::FindClass(env, "android/graphics/PointF");
- pointFClass = jni::NewGlobalRef(env, pointFClass).release();
- pointFConstructorId = &jni::GetMethodID(env, *pointFClass, "<init>", "(FF)V");
- pointFXId = &jni::GetFieldID(env, *pointFClass, "x", "F");
- pointFYId = &jni::GetFieldID(env, *pointFClass, "y", "F");
-
- rectFClass = &jni::FindClass(env, "android/graphics/RectF");
- rectFClass = jni::NewGlobalRef(env, rectFClass).release();
- rectFConstructorId = &jni::GetMethodID(env, *rectFClass, "<init>", "()V");
- rectFLeftId = &jni::GetFieldID(env, *rectFClass, "left", "F");
- rectFRightId = &jni::GetFieldID(env, *rectFClass, "right", "F");
- rectFTopId = &jni::GetFieldID(env, *rectFClass, "top", "F");
- rectFBottomId = &jni::GetFieldID(env, *rectFClass, "bottom", "F");
-
- jni::jclass& nativeMapViewClass = jni::FindClass(env, "com/mapbox/mapboxsdk/maps/NativeMapView");
-
- onInvalidateId = &jni::GetMethodID(env, nativeMapViewClass, "onInvalidate", "()V");
- onMapChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onMapChanged", "(I)V");
- onFpsChangedId = &jni::GetMethodID(env, nativeMapViewClass, "onFpsChanged", "(D)V");
- onSnapshotReadyId = &jni::GetMethodID(env, nativeMapViewClass, "onSnapshotReady","([B)V");
-
- #define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
-
- jni::RegisterNatives(env, nativeMapViewClass,
- MAKE_NATIVE_METHOD(nativeCreate, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;FIJ)J"),
- MAKE_NATIVE_METHOD(nativeDestroy, "(J)V"),
- MAKE_NATIVE_METHOD(nativeInitializeDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateDisplay, "(J)V"),
- MAKE_NATIVE_METHOD(nativeInitializeContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"),
- MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"),
- MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"),
- MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"),
- MAKE_NATIVE_METHOD(nativeRender, "(J)V"),
- MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"),
- MAKE_NATIVE_METHOD(nativeFramebufferResize, "(JII)V"),
- MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveClass, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeHasClass, "(JLjava/lang/String;)Z"),
- MAKE_NATIVE_METHOD(nativeSetClasses, "(JLjava/util/List;)V"),
- MAKE_NATIVE_METHOD(nativeGetClasses, "(J)Ljava/util/List;"),
- MAKE_NATIVE_METHOD(nativeSetStyleUrl, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetStyleUrl, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeSetStyleJson, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetStyleJson, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeSetAccessToken, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeGetAccessToken, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(nativeCancelTransitions, "(J)V"),
- MAKE_NATIVE_METHOD(nativeSetGestureInProgress, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeMoveBy, "(JDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetLatLng, "(JDDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetLatLng, "(J)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativeResetPosition, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetCameraValues, "(J)[D"),
- MAKE_NATIVE_METHOD(nativeGetPitch, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetPitch, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeScaleBy, "(JDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetScale, "(JDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetScale, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetZoom, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeGetZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeResetZoom, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetMinZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetMinZoom, "(JD)V"),
- MAKE_NATIVE_METHOD(nativeGetMaxZoom, "(J)D"),
- MAKE_NATIVE_METHOD(nativeSetMaxZoom, "(JD)V"),
- MAKE_NATIVE_METHOD(nativeRotateBy, "(JDDDDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetBearing, "(JDJ)V"),
- MAKE_NATIVE_METHOD(nativeSetBearingXY, "(JDDD)V"),
- MAKE_NATIVE_METHOD(nativeGetBearing, "(J)D"),
- MAKE_NATIVE_METHOD(nativeResetNorth, "(J)V"),
- MAKE_NATIVE_METHOD(nativeAddMarkers, "(J[Lcom/mapbox/mapboxsdk/annotations/Marker;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolylines, "(J[Lcom/mapbox/mapboxsdk/annotations/Polyline;)[J"),
- MAKE_NATIVE_METHOD(nativeAddPolygons, "(J[Lcom/mapbox/mapboxsdk/annotations/Polygon;)[J"),
- MAKE_NATIVE_METHOD(nativeUpdateMarker, "(JJDDLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeUpdatePolygon, "(JJLcom/mapbox/mapboxsdk/annotations/Polygon;)V"),
- MAKE_NATIVE_METHOD(nativeUpdatePolyline, "(JJLcom/mapbox/mapboxsdk/annotations/Polyline;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveAnnotations, "(J[J)V"),
- MAKE_NATIVE_METHOD(nativeQueryPointAnnotations, "(JLandroid/graphics/RectF;)[J"),
- MAKE_NATIVE_METHOD(nativeAddAnnotationIcon, "(JLjava/lang/String;IIF[B)V"),
- MAKE_NATIVE_METHOD(nativeSetVisibleCoordinateBounds, "(J[Lcom/mapbox/mapboxsdk/geometry/LatLng;Landroid/graphics/RectF;DJ)V"),
- MAKE_NATIVE_METHOD(nativeOnLowMemory, "(J)V"),
- MAKE_NATIVE_METHOD(nativeSetDebug, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeToggleDebug, "(J)V"),
- MAKE_NATIVE_METHOD(nativeGetDebug, "(J)Z"),
- MAKE_NATIVE_METHOD(nativeIsFullyLoaded, "(J)Z"),
- MAKE_NATIVE_METHOD(nativeSetReachability, "(JZ)V"),
- MAKE_NATIVE_METHOD(nativeGetMetersPerPixelAtLatitude, "(JDD)D"),
- MAKE_NATIVE_METHOD(nativeProjectedMetersForLatLng, "(JDD)Lcom/mapbox/mapboxsdk/geometry/ProjectedMeters;"),
- MAKE_NATIVE_METHOD(nativeLatLngForProjectedMeters, "(JDD)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativePixelForLatLng, "(JDD)Landroid/graphics/PointF;"),
- MAKE_NATIVE_METHOD(nativeLatLngForPixel, "(JFF)Lcom/mapbox/mapboxsdk/geometry/LatLng;"),
- MAKE_NATIVE_METHOD(nativeGetTopOffsetPixelsForAnnotationSymbol, "(JLjava/lang/String;)D"),
- MAKE_NATIVE_METHOD(nativeJumpTo, "(JDDDDD)V"),
- MAKE_NATIVE_METHOD(nativeEaseTo, "(JDDDJDDZ)V"),
- MAKE_NATIVE_METHOD(nativeFlyTo, "(JDDDJDD)V"),
- MAKE_NATIVE_METHOD(nativeGetTransitionDuration, "(J)J"),
- MAKE_NATIVE_METHOD(nativeSetTransitionDuration, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetTransitionDelay, "(J)J"),
- MAKE_NATIVE_METHOD(nativeSetTransitionDelay, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetLayer, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/layers/Layer;"),
- MAKE_NATIVE_METHOD(nativeAddLayer, "(JJLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveLayerById, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveLayer, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeGetSource, "(JLjava/lang/String;)Lcom/mapbox/mapboxsdk/style/sources/Source;"),
- MAKE_NATIVE_METHOD(nativeAddSource, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeRemoveSourceById, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeRemoveSource, "(JJ)V"),
- MAKE_NATIVE_METHOD(nativeAddImage, "(JLjava/lang/String;IIF[B)V"),
- MAKE_NATIVE_METHOD(nativeRemoveImage, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(nativeSetContentPadding, "(JDDDD)V"),
- MAKE_NATIVE_METHOD(nativeScheduleTakeSnapshot, "(J)V"),
- MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForPoint, "(JFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"),
- MAKE_NATIVE_METHOD(nativeQueryRenderedFeaturesForBox, "(JFFFF[Ljava/lang/String;)[Lcom/mapbox/services/commons/geojson/Feature;"),
- MAKE_NATIVE_METHOD(nativeSetAPIBaseURL, "(JLjava/lang/String;)V")
- );
+ java::util::registerNative(env);
+ PointF::registerNative(env);
+ RectF::registerNative(env);
- // Offline begin
+ // Geometry
+ Feature::registerNative(env);
+ LatLng::registerNative(env);
+ LatLngBounds::registerNative(env);
+ ProjectedMeters::registerNative(env);
- struct OfflineManager {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; }
+ //Annotation
+ Marker::registerNative(env);
+ Polygon::registerNative(env);
+ Polyline::registerNative(env);
- struct ListOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback"; }
- };
+ // Map
+ NativeMapView::registerNative(env);
- struct CreateOfflineRegionsCallback {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
- };
- };
+ // Http
+ RegisterNativeHTTPRequest(env);
- struct OfflineRegion {
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; }
- };
+ // Bitmap
+ Bitmap::registerNative(env);
+ BitmapFactory::registerNative(env);
- jni::Class<OfflineManager> offlineManagerClass = jni::Class<OfflineManager>::Find(env);
- offlineManagerClassPtrId = &jni::GetFieldID(env, offlineManagerClass, "mDefaultFileSourcePtr", "J");
-
- jni::RegisterNatives(env, offlineManagerClass,
- MAKE_NATIVE_METHOD(createDefaultFileSource, "(Ljava/lang/String;Ljava/lang/String;J)J"),
- MAKE_NATIVE_METHOD(setAccessToken, "(JLjava/lang/String;)V"),
- MAKE_NATIVE_METHOD(getAccessToken, "(J)Ljava/lang/String;"),
- MAKE_NATIVE_METHOD(listOfflineRegions, "(JLcom/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback;)V"),
- MAKE_NATIVE_METHOD(createOfflineRegion, "(JLcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;[BLcom/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback;)V"),
- MAKE_NATIVE_METHOD(setOfflineMapboxTileCountLimit, "(JJ)V")
- );
-
- jni::Class<OfflineManager::ListOfflineRegionsCallback> listOfflineRegionsCallbackClass = jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env);
- listOnListMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onList", "([Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- listOnErrorMethodId = &jni::GetMethodID(env, listOfflineRegionsCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::Class<OfflineManager::CreateOfflineRegionsCallback> createOfflineRegionCallbackClass = jni::Class<OfflineManager::CreateOfflineRegionsCallback>::Find(env);
- createOnCreateMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onCreate", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion;)V");
- createOnErrorMethodId = &jni::GetMethodID(env, createOfflineRegionCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- offlineRegionClass = &jni::FindClass(env, OfflineRegion::Name());
- offlineRegionClass = jni::NewGlobalRef(env, offlineRegionClass).release();
- offlineRegionConstructorId = &jni::GetMethodID(env, *offlineRegionClass, "<init>", "()V");
- offlineRegionOfflineManagerId = &jni::GetFieldID(env, *offlineRegionClass, "offlineManager", "Lcom/mapbox/mapboxsdk/offline/OfflineManager;");
- offlineRegionIdId = &jni::GetFieldID(env, *offlineRegionClass, "mId", "J");
- offlineRegionDefinitionId = &jni::GetFieldID(env, *offlineRegionClass, "mDefinition", "Lcom/mapbox/mapboxsdk/offline/OfflineRegionDefinition;");
- offlineRegionMetadataId = &jni::GetFieldID(env, *offlineRegionClass, "mMetadata", "[B");
- offlineRegionPtrId = &jni::GetFieldID(env, *offlineRegionClass, "mOfflineRegionPtr", "J");
-
- jni::RegisterNatives(env, *offlineRegionClass,
- MAKE_NATIVE_METHOD(destroyOfflineRegion, "()V"),
- MAKE_NATIVE_METHOD(setOfflineRegionObserver, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver;)V"),
- MAKE_NATIVE_METHOD(setOfflineRegionDownloadState, "(I)V"),
- MAKE_NATIVE_METHOD(getOfflineRegionStatus, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback;)V"),
- MAKE_NATIVE_METHOD(deleteOfflineRegion, "(Lcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback;)V"),
- MAKE_NATIVE_METHOD(updateOfflineRegionMetadata, "([BLcom/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback;)V")
- );
-
- // This needs to be updated once we support more than one type of region definition
- offlineRegionDefinitionClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition");
- offlineRegionDefinitionClass = jni::NewGlobalRef(env, offlineRegionDefinitionClass).release();
- offlineRegionDefinitionConstructorId = &jni::GetMethodID(env, *offlineRegionDefinitionClass, "<init>", "()V");
- offlineRegionDefinitionStyleURLId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "styleURL", "Ljava/lang/String;");
- offlineRegionDefinitionBoundsId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "bounds", "Lcom/mapbox/mapboxsdk/geometry/LatLngBounds;");
- offlineRegionDefinitionMinZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "minZoom", "D");
- offlineRegionDefinitionMaxZoomId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "maxZoom", "D");
- offlineRegionDefinitionPixelRatioId = &jni::GetFieldID(env, *offlineRegionDefinitionClass, "pixelRatio", "F");
-
- jni::jclass* offlineRegionObserverClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver");
- offlineRegionObserveronStatusChangedId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onStatusChanged", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionObserveronErrorId = &jni::GetMethodID(env, *offlineRegionObserverClass, "onError", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionError;)V");
- offlineRegionObserveronLimitId = &jni::GetMethodID(env, *offlineRegionObserverClass, "mapboxTileCountLimitExceeded", "(J)V");
-
- offlineRegionStatusClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionStatus");
- offlineRegionStatusClass = jni::NewGlobalRef(env, offlineRegionStatusClass).release();
- offlineRegionStatusConstructorId = &jni::GetMethodID(env, *offlineRegionStatusClass, "<init>", "()V");
- offlineRegionStatusDownloadStateId = &jni::GetFieldID(env, *offlineRegionStatusClass, "downloadState", "I");
- offlineRegionStatusCompletedResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceCount", "J");
- offlineRegionStatusCompletedResourceSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedResourceSize", "J");
- offlineRegionStatusCompletedTileCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileCount", "J");
- offlineRegionStatusCompletedTileSizeId = &jni::GetFieldID(env, *offlineRegionStatusClass, "completedTileSize", "J");
- offlineRegionStatusRequiredResourceCountId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCount", "J");
- offlineRegionStatusRequiredResourceCountIsPreciseId = &jni::GetFieldID(env, *offlineRegionStatusClass, "requiredResourceCountIsPrecise", "Z");
-
- offlineRegionErrorClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegionError");
- offlineRegionErrorClass = jni::NewGlobalRef(env, offlineRegionErrorClass).release();
- offlineRegionErrorConstructorId = &jni::GetMethodID(env, *offlineRegionErrorClass, "<init>", "()V");
- offlineRegionErrorReasonId = &jni::GetFieldID(env, *offlineRegionErrorClass, "reason", "Ljava/lang/String;");
- offlineRegionErrorMessageId = &jni::GetFieldID(env, *offlineRegionErrorClass, "message", "Ljava/lang/String;");
-
- jni::jclass* offlineRegionStatusCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback");
- offlineRegionStatusOnStatusId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onStatus", "(Lcom/mapbox/mapboxsdk/offline/OfflineRegionStatus;)V");
- offlineRegionStatusOnErrorId = &jni::GetMethodID(env, *offlineRegionStatusCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionDeleteCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback");
- offlineRegionDeleteOnDeleteId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onDelete", "()V");
- offlineRegionDeleteOnErrorId = &jni::GetMethodID(env, *offlineRegionDeleteCallbackClass, "onError", "(Ljava/lang/String;)V");
-
- jni::jclass* offlineRegionUpdateMetadataCallbackClass = &jni::FindClass(env, "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback");
- updateMetadataOnUpdateMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onUpdate", "([B)V");
- updateMetadataOnErrorMethodId = &jni::GetMethodID(env, *offlineRegionUpdateMetadataCallbackClass, "onError", "(Ljava/lang/String;)V");
+ // Style
+ registerNativeLayers(env);
+ registerNativeSources(env);
+ Stop::registerNative(env);
+ CategoricalStops::registerNative(env);
+ ExponentialStops::registerNative(env);
+ IdentityStops::registerNative(env);
+ IntervalStops::registerNative(env);
- // Offline end
+ // Connectivity
+ ConnectivityListener::registerNative(env);
- char release[PROP_VALUE_MAX] = "";
- __system_property_get("ro.build.version.release", release);
- androidRelease = std::string(release);
+ // Offline
+ OfflineManager::registerNative(env);
+ OfflineRegion::registerNative(env);
+ OfflineRegionDefinition::registerNative(env);
+ OfflineTilePyramidRegionDefinition::registerNative(env);
+ OfflineRegionError::registerNative(env);
+ OfflineRegionStatus::registerNative(env);
}
-
-} // android
-} // mbgl
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index 90ec914cf2..f0c113f754 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -14,17 +14,11 @@ extern JavaVM* theJVM;
extern std::string cachePath;
extern std::string dataPath;
extern std::string apkPath;
-extern std::string androidRelease;
-extern jmethodID onInvalidateId;
-extern jmethodID onMapChangedId;
-extern jmethodID onFpsChangedId;
-extern jmethodID onSnapshotReadyId;
+bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
+void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-extern bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
-extern void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-
extern void registerNatives(JavaVM* vm);
-} //android
-} //mbgl
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni/generic_global_ref_deleter.hpp b/platform/android/src/jni/generic_global_ref_deleter.hpp
new file mode 100644
index 0000000000..4e53e0a0ce
--- /dev/null
+++ b/platform/android/src/jni/generic_global_ref_deleter.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <jni/jni.hpp>
+
+#include "../attach_env.hpp"
+
+namespace mbgl {
+namespace android {
+
+// A deleter that doesn't retain an JNIEnv handle but instead tries to attach the JVM. This means
+// it can be used on any thread to delete a global ref.
+struct GenericGlobalRefDeleter {
+ void operator()(jni::jobject* p) const {
+ if (p) {
+ auto env = AttachEnv();
+ env->DeleteGlobalRef(jni::Unwrap(p));
+ }
+ }
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 9d467f6ede..1930d1854d 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -1,5 +1,4 @@
#include "native_map_view.hpp"
-#include "jni.hpp"
#include <cstdlib>
#include <ctime>
@@ -10,90 +9,91 @@
#include <sys/system_properties.h>
-#include <mbgl/util/platform.hpp>
-#include <mbgl/util/event.hpp>
-#include <mbgl/util/logging.hpp>
-#include <mbgl/gl/extension.hpp>
+#include <EGL/egl.h>
+#include <android/native_window_jni.h>
+
+#include <jni/jni.hpp>
+
#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/extension.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/event.hpp>
+#include <mbgl/util/exception.hpp>
+#include <mbgl/util/geo.hpp>
#include <mbgl/util/image.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/sprite/sprite_image.hpp>
-namespace mbgl {
-namespace android {
-
-NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_)
- : env(env_),
- availableProcessors(availableProcessors_),
- totalMemory(totalMemory_),
- threadPool(4) {
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "geometry/conversion/feature.hpp"
- assert(env_ != nullptr);
- assert(obj_ != nullptr);
+#include "jni.hpp"
+#include "attach_env.hpp"
+#include "bitmap.hpp"
+#include "run_loop_impl.hpp"
+#include "java/util.hpp"
- if (env->GetJavaVM(&vm) < 0) {
- env->ExceptionDescribe();
- return;
- }
+namespace mbgl {
+namespace android {
- obj = env->NewWeakGlobalRef(obj_);
- if (obj == nullptr) {
- env->ExceptionDescribe();
+NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object<NativeMapView> _obj, jni::Object<FileSource> jFileSource,
+ jni::jfloat _pixelRatio, jni::jint _availableProcessors, jni::jlong _totalMemory) :
+ javaPeer(_obj.NewWeakGlobalRef(_env)),
+ pixelRatio(_pixelRatio),
+ availableProcessors(_availableProcessors),
+ totalMemory(_totalMemory),
+ threadPool(sharedThreadPool()) {
+
+ // Get a reference to the JavaVM for callbacks
+ if (_env.GetJavaVM(&vm) < 0) {
+ _env.ExceptionDescribe();
return;
}
- fileSource = std::make_unique<mbgl::DefaultFileSource>(
- mbgl::android::cachePath + "/mbgl-offline.db",
- mbgl::android::apkPath);
-
+ // Create the core map
map = std::make_unique<mbgl::Map>(
*this, mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) },
- pixelRatio, *fileSource, threadPool, MapMode::Continuous);
+ pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource)
+ , *threadPool, MapMode::Continuous);
+ //Calculate a fitting cache size based on device parameters
float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1;
float cpuFactor = availableProcessors;
float memoryFactor = static_cast<float>(totalMemory) / 1000.0f / 1000.0f / 1000.0f;
float sizeFactor = (static_cast<float>(map->getSize().width) / mbgl::util::tileSize) *
- (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
-
- size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f;
+ (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
- map->setSourceTileCacheSize(cacheSize);
+ map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f);
}
+/**
+ * Called through NativeMapView#destroy()
+ */
NativeMapView::~NativeMapView() {
- terminateContext();
- destroySurface();
- terminateDisplay();
-
- assert(vm != nullptr);
- assert(obj != nullptr);
+ _terminateContext();
+ _destroySurface();
+ _terminateDisplay();
map.reset();
- fileSource.reset();
-
- env->DeleteWeakGlobalRef(obj);
- obj = nullptr;
- env = nullptr;
vm = nullptr;
}
-mbgl::Size NativeMapView::getFramebufferSize() const {
- return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
-}
-
-void NativeMapView::updateViewBinding() {
- getContext().bindFramebuffer.setCurrentValue(0);
- assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
- getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
- assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
-}
-
+/**
+ * From mbgl::View
+ */
void NativeMapView::bind() {
getContext().bindFramebuffer = 0;
getContext().viewport = { 0, 0, getFramebufferSize() };
}
+/**
+ * From mbgl::Backend.
+ */
void NativeMapView::activate() {
if (active++) {
return;
@@ -122,6 +122,9 @@ void NativeMapView::activate() {
}
}
+/**
+ * From mbgl::Backend.
+ */
void NativeMapView::deactivate() {
if (--active) {
return;
@@ -146,17 +149,57 @@ void NativeMapView::deactivate() {
}
}
+/**
+ * From mbgl::Backend. Callback to java NativeMapView#onInvalidate().
+ *
+ * May be called from any thread
+ */
void NativeMapView::invalidate() {
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onInvalidate = javaClass.GetMethod<void ()>(*_env, "onInvalidate");
+ javaPeer->Call(*_env, onInvalidate);
+}
+
+/**
+ * From mbgl::Backend. Callback to java NativeMapView#onMapChanged(int).
+ *
+ * May be called from any thread
+ */
+void NativeMapView::notifyMapChange(mbgl::MapChange change) {
assert(vm != nullptr);
- assert(obj != nullptr);
- env->CallVoidMethod(obj, onInvalidateId);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onMapChanged = javaClass.GetMethod<void (int)>(*_env, "onMapChanged");
+ javaPeer->Call(*_env, onMapChanged, (int) change);
+}
+
+// JNI Methods //
+
+void NativeMapView::initializeDisplay(jni::JNIEnv&) {
+ _initializeDisplay();
}
-void NativeMapView::render() {
+void NativeMapView::terminateDisplay(jni::JNIEnv&) {
+ _terminateDisplay();
+}
+
+void NativeMapView::initializeContext(jni::JNIEnv&) {
+ _initializeContext();
+}
+
+void NativeMapView::terminateContext(jni::JNIEnv&) {
+ _terminateContext();
+}
+
+void NativeMapView::createSurface(jni::JNIEnv& env, jni::Object<> _surface) {
+ _createSurface(ANativeWindow_fromSurface(&env, jni::Unwrap(*_surface)));
+}
+
+void NativeMapView::destroySurface(jni::JNIEnv&) {
+ _destroySurface();
+}
+
+void NativeMapView::render(jni::JNIEnv& env) {
BackendScope guard(*this);
if (framebufferSizeChanged) {
@@ -172,17 +215,12 @@ void NativeMapView::render() {
// take snapshot
auto image = getContext().readFramebuffer<mbgl::PremultipliedImage>(getFramebufferSize());
-
- // encode and convert to jbytes
- std::string string = encodePNG(image);
- jbyteArray arr = env->NewByteArray(string.length());
- env->SetByteArrayRegion(arr,0,string.length(),(jbyte*)string.c_str());
+ auto bitmap = Bitmap::CreateBitmap(env, std::move(image));
// invoke Mapview#OnSnapshotReady
- env->CallVoidMethod(obj, onSnapshotReadyId, arr);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onSnapshotReady = javaClass.GetMethod<void (jni::Object<Bitmap>)>(*_env, "onSnapshotReady");
+ javaPeer->Call(*_env, onSnapshotReady, bitmap);
}
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
@@ -198,11 +236,736 @@ void NativeMapView::render() {
}
}
-mbgl::Map &NativeMapView::getMap() { return *map; }
+void NativeMapView::update(jni::JNIEnv&) {
+ invalidate();
+}
+
+void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
+ width = w;
+ height = h;
+ map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
+}
+
+void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
+ fbWidth = w;
+ fbHeight = h;
+ framebufferSizeChanged = true;
+ invalidate();
+}
+
+jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleURL());
+}
+
+void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
+ map->setStyleURL(jni::Make<std::string>(env, url));
+}
+
+jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, map->getStyleJSON());
+}
+
+void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
+ map->setStyleJSON(jni::Make<std::string>(env, json));
+}
+
+void NativeMapView::cancelTransitions(jni::JNIEnv&) {
+ map->cancelTransitions();
+}
+
+void NativeMapView::setGestureInProgress(jni::JNIEnv&, jni::jboolean inProgress) {
+ map->setGestureInProgress(inProgress);
+}
+
+void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::jlong duration) {
+ mbgl::AnimationOptions animationOptions;
+ if (duration > 0) {
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0.3, 0.6, 1.0 });
+ }
+ map->moveBy({dx, dy}, animationOptions);
+}
+
+void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions options;
+ if (angle != -1) {
+ options.angle = (-angle * M_PI) / 180;
+ }
+ options.center = mbgl::LatLng(latitude, longitude);
+ options.padding = insets;
+ if (pitch != -1) {
+ options.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ options.zoom = zoom;
+ }
+
+ map->jumpTo(options);
+}
+
+void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ if (pitch != -1) {
+ cameraOptions.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ cameraOptions.zoom = zoom;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ animationOptions.duration.emplace(mbgl::Duration(duration));
+ if (!easing) {
+ // add a linear interpolator instead of easing
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0, 0, 1, 1 });
+ }
+
+ map->easeTo(cameraOptions, animationOptions);
+}
+
+void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble angle, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
+ mbgl::CameraOptions cameraOptions;
+ if (angle != -1) {
+ cameraOptions.angle = (-angle * M_PI) / 180 ;
+ }
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ cameraOptions.padding = insets;
+ if (pitch != -1) {
+ cameraOptions.pitch = pitch * M_PI / 180;
+ }
+ if (zoom != -1) {
+ cameraOptions.zoom = zoom;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ animationOptions.duration.emplace(mbgl::Duration(duration));
+ map->flyTo(cameraOptions, animationOptions);
+}
+
+jni::Object<LatLng> NativeMapView::getLatLng(JNIEnv& env) {
+ mbgl::LatLng latLng = map->getLatLng(insets);
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration) {
+ map->setLatLng(mbgl::LatLng(latitude, longitude), insets, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
+ if (reachable) {
+ mbgl::NetworkStatus::Reachable();
+ }
+}
+
+void NativeMapView::resetPosition(jni::JNIEnv&) {
+ map->resetPosition();
+}
+
+jni::jdouble NativeMapView::getPitch(jni::JNIEnv&) {
+ return map->getPitch();
+}
+
+void NativeMapView::setPitch(jni::JNIEnv&, jni::jdouble pitch, jni::jlong duration) {
+ map->setPitch(pitch, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::scaleBy(jni::JNIEnv&, jni::jdouble ds, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->scaleBy(ds, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setScale(jni::JNIEnv&, jni::jdouble scale, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setScale(scale, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getScale(jni::JNIEnv&) {
+ return map->getScale();
+}
+
+void NativeMapView::setZoom(jni::JNIEnv&, jni::jdouble zoom, jni::jlong duration) {
+ map->setZoom(zoom, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getZoom(jni::JNIEnv&) {
+ return map->getZoom();
+}
+
+void NativeMapView::resetZoom(jni::JNIEnv&) {
+ map->resetZoom();
+}
+
+void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
+ map->setMinZoom(zoom);
+}
+
+jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
+ return map->getMinZoom();
+}
+
+void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
+ map->setMaxZoom(zoom);
+}
+
+jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
+ return map->getMaxZoom();
+}
+
+void NativeMapView::rotateBy(jni::JNIEnv&, jni::jdouble sx, jni::jdouble sy, jni::jdouble ex, jni::jdouble ey, jni::jlong duration) {
+ mbgl::ScreenCoordinate first(sx, sy);
+ mbgl::ScreenCoordinate second(ex, ey);
+ map->rotateBy(first, second, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setBearing(jni::JNIEnv&, jni::jdouble degrees, jni::jlong duration) {
+ map->setBearing(degrees, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+void NativeMapView::setBearingXY(jni::JNIEnv&, jni::jdouble degrees, jni::jdouble cx, jni::jdouble cy, jni::jlong duration) {
+ mbgl::ScreenCoordinate center(cx, cy);
+ map->setBearing(degrees, center, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+}
+
+jni::jdouble NativeMapView::getBearing(jni::JNIEnv&) {
+ return map->getBearing();
+}
+
+void NativeMapView::resetNorth(jni::JNIEnv&) {
+ map->resetNorth();
+}
+
+void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, jni::Array<jni::Object<LatLng>> coordinates, jni::Object<RectF> padding, jdouble direction, jni::jlong duration) {
+ NullCheck(env, &coordinates);
+ std::size_t count = coordinates.Length(env);
+
+ std::vector<mbgl::LatLng> latLngs;
+ latLngs.reserve(count);
+
+ for (std::size_t i = 0; i < count; i++) {
+ auto latLng = coordinates.Get(env, i);
+ latLngs.push_back(LatLng::getLatLng(env, latLng));
+ jni::DeleteLocalRef(env, latLng);
+ }
+
+ mbgl::EdgeInsets mbglInsets = { RectF::getTop(env, padding), RectF::getLeft(env, padding), RectF::getBottom(env, padding), RectF::getRight(env, padding) };
+ mbgl::CameraOptions cameraOptions = map->cameraForLatLngs(latLngs, mbglInsets);
+ if (direction >= 0) {
+ // convert from degrees to radians
+ cameraOptions.angle = (-direction * M_PI) / 180;
+ }
+
+ mbgl::AnimationOptions animationOptions;
+ if (duration > 0) {
+ animationOptions.duration.emplace(mbgl::Milliseconds(duration));
+ // equivalent to kCAMediaTimingFunctionDefault in iOS
+ animationOptions.easing.emplace(mbgl::util::UnitBezier { 0.25, 0.1, 0.25, 0.1 });
+ }
+
+ map->easeTo(cameraOptions, animationOptions);
+}
+
+void NativeMapView::setContentPadding(JNIEnv&, double top, double left, double bottom, double right) {
+ insets = {top, left, bottom, right};
+}
+
+void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
+ snapshot = true;
+}
+
+void NativeMapView::enableFps(jni::JNIEnv&, jni::jboolean enable) {
+ fpsEnabled = enable;
+}
+
+jni::Array<jni::jdouble> NativeMapView::getCameraValues(jni::JNIEnv& env) {
+ //Create buffer with values
+ jdouble buf[5];
+ mbgl::LatLng latLng = map->getLatLng(insets);
+ buf[0] = latLng.latitude;
+ buf[1] = latLng.longitude;
+ buf[2] = -map->getBearing();
+ buf[3] = map->getPitch();
+ buf[4] = map->getZoom();
+
+ //Convert to Java array
+ auto output = jni::Array<jni::jdouble>::New(env, 5);
+ jni::SetArrayRegion(env, *output, 0, 5, buf);
+
+ return output;
+}
+
+void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, jni::String jid) {
+ if (markerId == -1) {
+ return;
+ }
+
+ std::string iconId = jni::Make<std::string>(env, jid);
+ // Because Java only has int, not unsigned int, we need to bump the annotation id up to a long.
+ map->updateAnnotation(markerId, mbgl::SymbolAnnotation { mbgl::Point<double>(lon, lat), iconId });
+}
+
+jni::Array<jni::jlong> NativeMapView::addMarkers(jni::JNIEnv& env, jni::Array<jni::Object<Marker>> jmarkers) {
+ jni::NullCheck(env, &jmarkers);
+ std::size_t len = jmarkers.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ jni::Object<Marker> marker = jmarkers.Get(env, i);
+ ids.push_back(map->addAnnotation(mbgl::SymbolAnnotation {
+ Marker::getPosition(env, marker),
+ Marker::getIconId(env, marker)
+ }));
+
+ jni::DeleteLocalRef(env, marker);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+void NativeMapView::onLowMemory(JNIEnv&) {
+ map->onLowMemory();
+}
+
+using DebugOptions = mbgl::MapDebugOptions;
+
+void NativeMapView::setDebug(JNIEnv&, jni::jboolean debug) {
+ DebugOptions debugOptions = debug ? DebugOptions::TileBorders | DebugOptions::ParseStatus | DebugOptions::Collision
+ : DebugOptions::NoDebug;
+ map->setDebug(debugOptions);
+ fpsEnabled = debug;
+}
+
+void NativeMapView::cycleDebugOptions(JNIEnv&) {
+ map->cycleDebugOptions();
+ fpsEnabled = map->getDebug() != DebugOptions::NoDebug;
+}
+
+jni::jboolean NativeMapView::getDebug(JNIEnv&) {
+ return map->getDebug() != DebugOptions::NoDebug;
+}
+
+jni::jboolean NativeMapView::isFullyLoaded(JNIEnv&) {
+ return map->isFullyLoaded();
+}
+
+jni::jdouble NativeMapView::getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble lat, jni::jdouble zoom) {
+ return map->getMetersPerPixelAtLatitude(lat, zoom);
+}
+
+jni::Object<ProjectedMeters> NativeMapView::projectedMetersForLatLng(JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude) {
+ mbgl::ProjectedMeters projectedMeters = map->projectedMetersForLatLng(mbgl::LatLng(latitude, longitude));
+ return ProjectedMeters::New(env, projectedMeters.northing, projectedMeters.easting);
+}
+
+jni::Object<PointF> NativeMapView::pixelForLatLng(JNIEnv& env, jdouble latitude, jdouble longitude) {
+ mbgl::ScreenCoordinate pixel = map->pixelForLatLng(mbgl::LatLng(latitude, longitude));
+ return PointF::New(env, static_cast<float>(pixel.x), static_cast<float>(pixel.y));
+}
+
+jni::Object<LatLng> NativeMapView::latLngForProjectedMeters(JNIEnv& env, jdouble northing, jdouble easting) {
+ mbgl::LatLng latLng = map->latLngForProjectedMeters(mbgl::ProjectedMeters(northing, easting));
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+jni::Object<LatLng> NativeMapView::latLngForPixel(JNIEnv& env, jfloat x, jfloat y) {
+ mbgl::LatLng latLng = map->latLngForPixel(mbgl::ScreenCoordinate(x, y));
+ return LatLng::New(env, latLng.latitude, latLng.longitude);
+}
+
+jni::Array<jlong> NativeMapView::addPolylines(JNIEnv& env, jni::Array<jni::Object<Polyline>> polylines) {
+ NullCheck(env, &polylines);
+ std::size_t len = polylines.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ auto polyline = polylines.Get(env, i);
+
+ mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline);
+ ids.push_back(map->addAnnotation(annotation));
+
+ jni::DeleteLocalRef(env, polyline);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+
+jni::Array<jlong> NativeMapView::addPolygons(JNIEnv& env, jni::Array<jni::Object<Polygon>> polygons) {
+ NullCheck(env, &polygons);
+ std::size_t len = polygons.Length(env);
+
+ std::vector<jni::jlong> ids;
+ ids.reserve(len);
+
+ for (std::size_t i = 0; i < len; i++) {
+ auto polygon = polygons.Get(env, i);
+
+ mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon);
+ ids.push_back(map->addAnnotation(annotation));
+
+ jni::DeleteLocalRef(env, polygon);
+ }
+
+ auto result = jni::Array<jni::jlong>::New(env, len);
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, ids);
+
+ return result;
+}
+
+//TODO: Move to Polyline class and make native peer
+void NativeMapView::updatePolyline(JNIEnv& env, jlong polylineId, jni::Object<Polyline> polyline) {
+ mbgl::LineAnnotation annotation = Polyline::toAnnotation(env, polyline);
+ map->updateAnnotation(polylineId, annotation);
+}
+
+//TODO: Move to Polygon class and make native peer
+void NativeMapView::updatePolygon(JNIEnv& env, jlong polygonId, jni::Object<Polygon> polygon) {
+ mbgl::FillAnnotation annotation = Polygon::toAnnotation(env, polygon);
+ map->updateAnnotation(polygonId, annotation);
+}
+
+void NativeMapView::removeAnnotations(JNIEnv& env, jni::Array<jlong> ids) {
+ NullCheck(env, &ids);
+ std::size_t len = ids.Length(env);
+ auto elements = jni::GetArrayElements(env, *ids);
+ jlong* jids = std::get<0>(elements).get();
+
+ for (std::size_t i = 0; i < len; i++) {
+ if(jids[i] == -1L) {
+ continue;
+ }
+ map->removeAnnotation(jids[i]);
+ }
+}
+
+void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, jint h, jfloat scale, jni::Array<jbyte> jpixels) {
+ const std::string symbolName = jni::Make<std::string>(env, symbol);
+
+ NullCheck(env, &jpixels);
+ std::size_t size = jpixels.Length(env);
+
+ mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(w), static_cast<uint32_t>(h) });
+ if (premultipliedImage.bytes() != uint32_t(size)) {
+ throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
+ }
+
+ jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
+ auto iconImage = std::make_shared<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+ map->addAnnotationIcon(symbolName, iconImage);
+}
+
+jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
+ return map->getTopOffsetPixelsForAnnotationIcon(jni::Make<std::string>(env, symbolName));
+}
+
+jlong NativeMapView::getTransitionDuration(JNIEnv&) {
+ const auto transitionOptions = map->getTransitionOptions();
+ return transitionOptions.duration.value_or(mbgl::Duration::zero()).count();
+}
+
+void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) {
+ auto transitionOptions = map->getTransitionOptions();
+ transitionOptions.duration = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(duration));
+ map->setTransitionOptions(transitionOptions);
+}
+
+jlong NativeMapView::getTransitionDelay(JNIEnv&) {
+ const auto transitionOptions = map->getTransitionOptions();
+ return transitionOptions.delay.value_or(mbgl::Duration::zero()).count();
+}
+
+void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) {
+ auto transitionOptions = map->getTransitionOptions();
+ transitionOptions.delay = std::chrono::duration_cast<mbgl::Duration>(std::chrono::duration<jlong>(delay));
+ map->setTransitionOptions(transitionOptions);
+}
+
+jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<RectF> rect) {
+ // Convert input
+ mbgl::ScreenBox box = {
+ { RectF::getLeft(env, rect), RectF::getTop(env, rect) },
+ { RectF::getRight(env, rect), RectF::getBottom(env, rect) },
+ };
+
+ // Assume only points for now
+ mbgl::AnnotationIDs ids = map->queryPointAnnotations(box);
+
+ // Convert result
+ std::vector<jlong> longIds(ids.begin(), ids.end());
+ auto result = jni::Array<jni::jlong>::New(env, ids.size());
+ result.SetRegion<std::vector<jni::jlong>>(env, 0, longIds);
+
+ return result;
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ point<double> point = {x, y};
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(point, layers));
+}
+
+jni::Array<jni::Object<Feature>> NativeMapView::queryRenderedFeaturesForBox(JNIEnv& env, jni::jfloat left, jni::jfloat top, jni::jfloat right, jni::jfloat bottom, jni::Array<jni::String> layerIds) {
+ using namespace mbgl::android::conversion;
+ using namespace mapbox::geometry;
+
+ mbgl::optional<std::vector<std::string>> layers;
+ if (layerIds != nullptr && layerIds.Length(env) > 0) {
+ layers = toVector(env, layerIds);
+ }
+ box<double> box = { point<double>{ left, top}, point<double>{ right, bottom } };
+
+ return *convert<jni::Array<jni::Object<Feature>>, std::vector<mbgl::Feature>>(env, map->queryRenderedFeatures(box, layers));
+}
+
+jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
+
+ // Get the core layers
+ std::vector<style::Layer*> layers = map->getLayers();
+
+ // Convert
+ jni::Array<jni::Object<Layer>> jLayers = jni::Array<jni::Object<Layer>>::New(env, layers.size(), Layer::javaClass);
+ int index = 0;
+ for (auto layer : layers) {
+ auto jLayer = jni::Object<Layer>(createJavaLayerPeer(env, *map, *layer));
+ jLayers.Set(env, index, jLayer);
+ jni::DeleteLocalRef(env, jLayer);
+ index++;
+ }
+
+ return jLayers;
+}
+
+jni::Object<Layer> NativeMapView::getLayer(JNIEnv& env, jni::String layerId) {
+
+ // Find the layer
+ mbgl::style::Layer* coreLayer = map->getLayer(jni::Make<std::string>(env, layerId));
+ if (!coreLayer) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
+ return jni::Object<Layer>();
+ }
+
+ // Create and return the layer's native peer
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, *coreLayer));
+}
-mbgl::DefaultFileSource &NativeMapView::getFileSource() { return *fileSource; }
+void NativeMapView::addLayer(JNIEnv& env, jlong nativeLayerPtr, jni::String before) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+ try {
+ layer->addToMap(*map, before ? mbgl::optional<std::string>(jni::Make<std::string>(env, before)) : mbgl::optional<std::string>());
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, jni::String above) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+
+ // Find the sibling
+ auto layers = map->getLayers();
+ auto siblingId = jni::Make<std::string>(env, above);
+
+ size_t index = 0;
+ for (auto l : layers) {
+ if (l->getID() == siblingId) {
+ break;
+ }
+ index++;
+ }
+
+ // Check if we found a sibling to place before
+ mbgl::optional<std::string> before;
+ if (index + 1 > layers.size()) {
+ // Not found
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"),
+ std::string("Could not find layer: ").append(siblingId).c_str());
+ return;
+ } else if (index + 1 < layers.size()) {
+ // Place before the sibling
+ before = { layers.at(index + 1)->getID() };
+ }
+
+ // Add the layer
+ try {
+ layer->addToMap(*map, before);
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint index) {
+ assert(nativeLayerPtr != 0);
+
+ Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
+ auto layers = map->getLayers();
+
+ // Check index
+ int numLayers = layers.size() - 1;
+ if (index > numLayers || index < 0) {
+ Log::Error(Event::JNI, "Index out of range: %i", index);
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"),
+ std::string("Invalid index").c_str());
+ return;
+ }
+
+ // Insert it below the current at that index
+ try {
+ layer->addToMap(*map, layers.at(index)->getID());
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/CannotAddLayerException"), error.what());
+ }
+}
+
+/**
+ * Remove by layer id.
+ */
+jni::Object<Layer> NativeMapView::removeLayerById(JNIEnv& env, jni::String id) {
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(jni::Make<std::string>(env, id));
+ if (coreLayer) {
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
+ } else {
+ return jni::Object<Layer>();
+ }
+}
-void NativeMapView::initializeDisplay() {
+/**
+ * Remove layer at index.
+ */
+jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
+ auto layers = map->getLayers();
+
+ // Check index
+ int numLayers = layers.size() - 1;
+ if (index > numLayers || index < 0) {
+ Log::Warning(Event::JNI, "Index out of range: %i", index);
+ return jni::Object<Layer>();
+ }
+
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layers.at(index)->getID());
+ if (coreLayer) {
+ return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
+ } else {
+ return jni::Object<Layer>();
+ }
+}
+
+/**
+ * Remove with wrapper object id. Ownership is transferred back to the wrapper
+ */
+void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
+ assert(layerPtr != 0);
+
+ mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layer->get().getID());
+ if (coreLayer) {
+ layer->setLayer(std::move(coreLayer));
+ }
+}
+
+jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
+ // Get the core sources
+ std::vector<style::Source*> sources = map->getSources();
+
+ // Convert
+ jni::Array<jni::Object<Source>> jSources = jni::Array<jni::Object<Source>>::New(env, sources.size(), Source::javaClass);
+ int index = 0;
+ for (auto source : sources) {
+ auto jSource = jni::Object<Source>(createJavaSourcePeer(env, *map, *source));
+ jSources.Set(env, index, jSource);
+ jni::DeleteLocalRef(env, jSource);
+ index++;
+ }
+
+ return jSources;
+}
+
+jni::Object<Source> NativeMapView::getSource(JNIEnv& env, jni::String sourceId) {
+ // Find the source
+ mbgl::style::Source* coreSource = map->getSource(jni::Make<std::string>(env, sourceId));
+ if (!coreSource) {
+ mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
+ return jni::Object<Source>();
+ }
+
+ // Create and return the source's native peer
+ return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+}
+
+void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ Source *source = reinterpret_cast<Source *>(sourcePtr);
+ try {
+ source->addToMap(*map);
+ } catch (const std::runtime_error& error) {
+ jni::ThrowNew(env, jni::FindClass(env, "com/mapbox/mapboxsdk/style/sources/CannotAddSourceException"), error.what());
+ }
+}
+
+jni::Object<Source> NativeMapView::removeSourceById(JNIEnv& env, jni::String id) {
+ std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(jni::Make<std::string>(env, id));
+ if (coreSource) {
+ return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
+ } else {
+ return jni::Object<Source>();
+ }
+}
+
+void NativeMapView::removeSource(JNIEnv&, jlong sourcePtr) {
+ assert(sourcePtr != 0);
+
+ mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
+ std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(source->get().getID());
+ if (coreSource) {
+ source->setSource(std::move(coreSource));
+ }
+}
+
+void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::jint h, jni::jfloat scale, jni::Array<jbyte> pixels) {
+ jni::NullCheck(env, &pixels);
+ std::size_t size = pixels.Length(env);
+
+ mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(w), static_cast<uint32_t>(h) });
+ if (premultipliedImage.bytes() != uint32_t(size)) {
+ throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
+ }
+
+ jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
+ auto spriteImage = std::make_unique<mbgl::SpriteImage>(std::move(premultipliedImage), float(scale));
+
+ map->addImage(jni::Make<std::string>(env, name), std::move(spriteImage));
+}
+
+void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
+ map->removeImage(jni::Make<std::string>(env, name));
+}
+
+// Private methods //
+
+void NativeMapView::_initializeDisplay() {
assert(display == EGL_NO_DISPLAY);
assert(config == nullptr);
assert(format < 0);
@@ -287,145 +1050,6 @@ void NativeMapView::initializeDisplay() {
}
}
-void NativeMapView::terminateDisplay() {
- if (display != EGL_NO_DISPLAY) {
- // Destroy the surface first, if it still exists. This call needs a valid surface.
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- surface = EGL_NO_SURFACE;
- }
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (!eglTerminate(display)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
- eglGetError());
- throw std::runtime_error("eglTerminate() failed");
- }
- }
-
- display = EGL_NO_DISPLAY;
- config = nullptr;
- format = -1;
-}
-
-void NativeMapView::initializeContext() {
- assert(display != EGL_NO_DISPLAY);
- assert(context == EGL_NO_CONTEXT);
- assert(config != nullptr);
-
- const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
- if (context == EGL_NO_CONTEXT) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateContext() failed");
- }
-}
-
-void NativeMapView::terminateContext() {
- if (display != EGL_NO_DISPLAY) {
-
- if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
- mbgl::Log::Error(mbgl::Event::OpenGL,
- "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- if (context != EGL_NO_CONTEXT) {
- if (!eglDestroyContext(display, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroyContext() failed");
- }
- }
- }
-
- context = EGL_NO_CONTEXT;
-}
-
-void NativeMapView::createSurface(ANativeWindow *window_) {
- assert(window == nullptr);
- assert(window_ != nullptr);
- window = window_;
-
- assert(display != EGL_NO_DISPLAY);
- assert(surface == EGL_NO_SURFACE);
- assert(config != nullptr);
- assert(format >= 0);
-
- ANativeWindow_setBuffersGeometry(window, 0, 0, format);
-
- const EGLint surfaceAttribs[] = {EGL_NONE};
- surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
- if (surface == EGL_NO_SURFACE) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglCreateWindowSurface() failed");
- }
-
- if (!firstTime) {
- firstTime = true;
-
- BackendScope guard(*this);
-
- if (!eglMakeCurrent(display, surface, surface, context)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
- eglGetError());
- throw std::runtime_error("eglMakeCurrent() failed");
- }
-
- mbgl::gl::InitializeExtensions([] (const char * name) {
- return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
- });
- }
-}
-
-void NativeMapView::destroySurface() {
- if (surface != EGL_NO_SURFACE) {
- if (!eglDestroySurface(display, surface)) {
- mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
- eglGetError());
- throw std::runtime_error("eglDestroySurface() failed");
- }
- }
-
- surface = EGL_NO_SURFACE;
-
- if (window != nullptr) {
- ANativeWindow_release(window);
- window = nullptr;
- }
-}
-
-void NativeMapView::scheduleTakeSnapshot() {
- snapshot = true;
-}
-
-// Speed
-/*
-typedef enum {
- Format16Bit = 0,
- Format32BitNoAlpha = 1,
- Format32BitAlpha = 2,
- Format24Bit = 3,
- Unknown = 4
-} BufferFormat;
-
-typedef enum {
- Format16Depth8Stencil = 0,
- Format24Depth8Stencil = 1,
-} DepthStencilFormat;
-*/
-
// Quality
typedef enum {
Format16Bit = 3,
@@ -590,18 +1214,134 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi
return configId;
}
-void NativeMapView::notifyMapChange(mbgl::MapChange change) {
- assert(vm != nullptr);
- assert(obj != nullptr);
+void NativeMapView::_terminateDisplay() {
+ if (display != EGL_NO_DISPLAY) {
+ // Destroy the surface first, if it still exists. This call needs a valid surface.
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ surface = EGL_NO_SURFACE;
+ }
+
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (!eglTerminate(display)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglTerminate() failed");
+ }
+ }
+
+ display = EGL_NO_DISPLAY;
+ config = nullptr;
+ format = -1;
+}
- env->CallVoidMethod(obj, onMapChangedId, change);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
+void NativeMapView::_initializeContext() {
+ assert(display != EGL_NO_DISPLAY);
+ assert(context == EGL_NO_CONTEXT);
+ assert(config != nullptr);
+
+ const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
+ if (context == EGL_NO_CONTEXT) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateContext() failed");
}
}
-void NativeMapView::enableFps(bool enable) {
- fpsEnabled = enable;
+void NativeMapView::_terminateContext() {
+ if (display != EGL_NO_DISPLAY) {
+
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL,
+ "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ if (context != EGL_NO_CONTEXT) {
+ if (!eglDestroyContext(display, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroyContext() failed");
+ }
+ }
+ }
+
+ context = EGL_NO_CONTEXT;
+}
+
+void NativeMapView::_createSurface(ANativeWindow *window_) {
+ assert(window == nullptr);
+ assert(window_ != nullptr);
+ window = window_;
+
+ assert(display != EGL_NO_DISPLAY);
+ assert(surface == EGL_NO_SURFACE);
+ assert(config != nullptr);
+ assert(format >= 0);
+
+ ANativeWindow_setBuffersGeometry(window, 0, 0, format);
+
+ const EGLint surfaceAttribs[] = {EGL_NONE};
+ surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
+ if (surface == EGL_NO_SURFACE) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglCreateWindowSurface() failed");
+ }
+
+ if (firstRender) {
+ firstRender = false;
+
+ BackendScope guard(*this);
+
+ if (!eglMakeCurrent(display, surface, surface, context)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglMakeCurrent() failed");
+ }
+
+ mbgl::gl::InitializeExtensions([] (const char * name) {
+ return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
+ });
+ }
+}
+
+void NativeMapView::_destroySurface() {
+ if (surface != EGL_NO_SURFACE) {
+ if (!eglDestroySurface(display, surface)) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
+ eglGetError());
+ throw std::runtime_error("eglDestroySurface() failed");
+ }
+ }
+
+ surface = EGL_NO_SURFACE;
+
+ if (window != nullptr) {
+ ANativeWindow_release(window);
+ window = nullptr;
+ }
+}
+
+mbgl::Size NativeMapView::getFramebufferSize() const {
+ return { static_cast<uint32_t>(fbWidth), static_cast<uint32_t>(fbHeight) };
+}
+
+void NativeMapView::updateViewBinding() {
+ getContext().bindFramebuffer.setCurrentValue(0);
+ assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue());
+ getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() });
+ assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue());
}
void NativeMapView::updateFps() {
@@ -619,35 +1359,121 @@ void NativeMapView::updateFps() {
if (currentTime - timeElapsed >= 1) {
fps = frames / ((currentTime - timeElapsed) / 1E9);
- mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps);
+ mbgl::Log::Info(mbgl::Event::Render, "FPS: %4.2f", fps);
timeElapsed = currentTime;
frames = 0;
}
assert(vm != nullptr);
- assert(obj != nullptr);
-
- env->CallVoidMethod(obj, onFpsChangedId, fps);
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- }
-}
-void NativeMapView::resizeView(int w, int h) {
- width = w;
- height = h;
- map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
-}
-
-void NativeMapView::resizeFramebuffer(int w, int h) {
- fbWidth = w;
- fbHeight = h;
- framebufferSizeChanged = true;
- invalidate();
+ android::UniqueEnv _env = android::AttachEnv();
+ static auto onFpsChanged = javaClass.GetMethod<void (double)>(*_env, "onFpsChanged");
+ javaPeer->Call(*_env, onFpsChanged, fps);
}
-void NativeMapView::setInsets(mbgl::EdgeInsets insets_) {
- insets = insets_;
+// Static methods //
+
+jni::Class<NativeMapView> NativeMapView::javaClass;
+
+void NativeMapView::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ NativeMapView::javaClass = *jni::Class<NativeMapView>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
+ std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong>,
+ "nativeInitialize",
+ "nativeDestroy",
+ METHOD(&NativeMapView::render, "nativeRender"),
+ METHOD(&NativeMapView::update, "nativeUpdate"),
+ METHOD(&NativeMapView::resizeView, "nativeResizeView"),
+ METHOD(&NativeMapView::resizeFramebuffer, "nativeResizeFramebuffer"),
+ METHOD(&NativeMapView::initializeDisplay, "nativeInitializeDisplay"),
+ METHOD(&NativeMapView::terminateDisplay, "nativeTerminateDisplay"),
+ METHOD(&NativeMapView::initializeContext, "nativeInitializeContext"),
+ METHOD(&NativeMapView::terminateContext, "nativeTerminateContext"),
+ METHOD(&NativeMapView::createSurface, "nativeCreateSurface"),
+ METHOD(&NativeMapView::destroySurface, "nativeDestroySurface"),
+ METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"),
+ METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"),
+ METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"),
+ METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"),
+ METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"),
+ METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"),
+ METHOD(&NativeMapView::moveBy, "nativeMoveBy"),
+ METHOD(&NativeMapView::jumpTo, "nativeJumpTo"),
+ METHOD(&NativeMapView::easeTo, "nativeEaseTo"),
+ METHOD(&NativeMapView::flyTo, "nativeFlyTo"),
+ METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"),
+ METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"),
+ METHOD(&NativeMapView::setReachability, "nativeSetReachability"),
+ METHOD(&NativeMapView::resetPosition, "nativeResetPosition"),
+ METHOD(&NativeMapView::getPitch, "nativeGetPitch"),
+ METHOD(&NativeMapView::setPitch, "nativeSetPitch"),
+ METHOD(&NativeMapView::scaleBy, "nativeScaleBy"),
+ METHOD(&NativeMapView::getScale, "nativeGetScale"),
+ METHOD(&NativeMapView::setScale, "nativeSetScale"),
+ METHOD(&NativeMapView::getZoom, "nativeGetZoom"),
+ METHOD(&NativeMapView::setZoom, "nativeSetZoom"),
+ METHOD(&NativeMapView::resetZoom, "nativeResetZoom"),
+ METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"),
+ METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"),
+ METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"),
+ METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"),
+ METHOD(&NativeMapView::rotateBy, "nativeRotateBy"),
+ METHOD(&NativeMapView::setBearing, "nativeSetBearing"),
+ METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"),
+ METHOD(&NativeMapView::getBearing, "nativeGetBearing"),
+ METHOD(&NativeMapView::resetNorth, "nativeResetNorth"),
+ METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
+ METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
+ METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
+ METHOD(&NativeMapView::enableFps, "nativeSetEnableFps"),
+ METHOD(&NativeMapView::getCameraValues, "nativeGetCameraValues"),
+ METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
+ METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"),
+ METHOD(&NativeMapView::setDebug, "nativeSetDebug"),
+ METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"),
+ METHOD(&NativeMapView::getDebug, "nativeGetDebug"),
+ METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"),
+ METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"),
+ METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"),
+ METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"),
+ METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"),
+ METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"),
+ METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"),
+ METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"),
+ METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"),
+ METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"),
+ METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"),
+ METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"),
+ METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"),
+ METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"),
+ METHOD(&NativeMapView::getTransitionDuration, "nativeGetTransitionDuration"),
+ METHOD(&NativeMapView::setTransitionDuration, "nativeSetTransitionDuration"),
+ METHOD(&NativeMapView::getTransitionDelay, "nativeGetTransitionDelay"),
+ METHOD(&NativeMapView::setTransitionDelay, "nativeSetTransitionDelay"),
+ METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
+ METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
+ METHOD(&NativeMapView::getLayers, "nativeGetLayers"),
+ METHOD(&NativeMapView::getLayer, "nativeGetLayer"),
+ METHOD(&NativeMapView::addLayer, "nativeAddLayer"),
+ METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"),
+ METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"),
+ METHOD(&NativeMapView::removeLayerById, "nativeRemoveLayerById"),
+ METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"),
+ METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"),
+ METHOD(&NativeMapView::getSources, "nativeGetSources"),
+ METHOD(&NativeMapView::getSource, "nativeGetSource"),
+ METHOD(&NativeMapView::addSource, "nativeAddSource"),
+ METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"),
+ METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
+ METHOD(&NativeMapView::addImage, "nativeAddImage"),
+ METHOD(&NativeMapView::removeImage, "nativeRemoveImage")
+ );
}
}
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index e7379700a9..c38afd3e6c 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -1,71 +1,275 @@
#pragma once
+#include <mbgl/map/backend.hpp>
+#include <mbgl/map/camera.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
-#include <mbgl/map/backend.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/default_thread_pool.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/network_status.hpp>
+
+#include "file_source.hpp"
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
+#include "geometry/feature.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/projected_meters.hpp"
+#include "style/layers/layers.hpp"
+#include "style/sources/sources.hpp"
#include <string>
#include <jni.h>
#include <android/native_window.h>
#include <EGL/egl.h>
+#include <jni/jni.hpp>
namespace mbgl {
namespace android {
-class NativeMapView : public mbgl::View, public mbgl::Backend {
+class NativeMapView : public View, public Backend {
public:
- NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory);
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/NativeMapView"; };
+
+ static jni::Class<NativeMapView> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ NativeMapView(jni::JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::jint, jni::jlong);
+
virtual ~NativeMapView();
- mbgl::Size getFramebufferSize() const;
- void updateViewBinding();
+ // mbgl::View //
+
void bind() override;
- void invalidate() override;
+ // mbgl::Backend //
+ void invalidate() override;
void notifyMapChange(mbgl::MapChange) override;
- mbgl::Map &getMap();
- mbgl::DefaultFileSource &getFileSource();
+ // JNI //
- void initializeDisplay();
- void terminateDisplay();
+ void destroy(jni::JNIEnv&);
- void initializeContext();
- void terminateContext();
+ void render(jni::JNIEnv&);
- void createSurface(ANativeWindow *window);
- void destroySurface();
+ void update(jni::JNIEnv&);
- void render();
+ void resizeView(jni::JNIEnv&, int, int);
- void enableFps(bool enable);
- void updateFps();
+ void resizeFramebuffer(jni::JNIEnv&, int, int);
+
+ void initializeDisplay(jni::JNIEnv&);
+
+ void terminateDisplay(jni::JNIEnv&);
+
+ void initializeContext(jni::JNIEnv&);
+
+ void terminateContext(jni::JNIEnv&);
+
+ void createSurface(jni::JNIEnv&, jni::Object<>);
+
+ void destroySurface(jni::JNIEnv&);
+
+ jni::String getStyleUrl(jni::JNIEnv&);
+
+ void setStyleUrl(jni::JNIEnv&, jni::String);
+
+ jni::String getStyleJson(jni::JNIEnv&);
+
+ void setStyleJson(jni::JNIEnv&, jni::String);
+
+ void cancelTransitions(jni::JNIEnv&);
+
+ void setGestureInProgress(jni::JNIEnv&, jni::jboolean);
+
+ void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble);
+
+ void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, jni::jboolean);
+
+ void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble);
+
+ jni::Object<LatLng> getLatLng(JNIEnv&);
+
+ void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setReachability(jni::JNIEnv&, jni::jboolean);
+
+ void resetPosition(jni::JNIEnv&);
+
+ jni::jdouble getPitch(jni::JNIEnv&);
+
+ void setPitch(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void scaleBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setScale(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getScale(jni::JNIEnv&);
+
+ void setZoom(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ jni::jdouble getZoom(jni::JNIEnv&);
+
+ void resetZoom(jni::JNIEnv&);
+
+ void setMinZoom(jni::JNIEnv&, jni::jdouble);
+
+ jni::jdouble getMinZoom(jni::JNIEnv&);
+
+ void setMaxZoom(jni::JNIEnv&, jni::jdouble);
+
+ jni::jdouble getMaxZoom(jni::JNIEnv&);
+
+ void rotateBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ void setBearing(jni::JNIEnv&, jni::jdouble, jni::jlong);
+
+ void setBearingXY(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong);
+
+ jni::jdouble getBearing(jni::JNIEnv&);
+
+ void resetNorth(jni::JNIEnv&);
+
+ void setVisibleCoordinateBounds(JNIEnv&, jni::Array<jni::Object<LatLng>>, jni::Object<RectF>, jni::jdouble, jni::jlong);
+
+ void setContentPadding(JNIEnv&, double, double, double, double);
+
+ void scheduleSnapshot(jni::JNIEnv&);
+
+ void enableFps(jni::JNIEnv&, jni::jboolean enable);
+
+ jni::Array<jni::jdouble> getCameraValues(jni::JNIEnv&);
+
+ void updateMarker(jni::JNIEnv&, jni::jlong, jni::jdouble, jni::jdouble, jni::String);
+
+ jni::Array<jni::jlong> addMarkers(jni::JNIEnv&, jni::Array<jni::Object<Marker>>);
+
+ void onLowMemory(JNIEnv& env);
+
+ void setDebug(JNIEnv&, jni::jboolean);
- void resizeView(int width, int height);
- void resizeFramebuffer(int width, int height);
- mbgl::EdgeInsets getInsets() { return insets;}
- void setInsets(mbgl::EdgeInsets insets_);
+ void cycleDebugOptions(JNIEnv&);
- void scheduleTakeSnapshot();
+ jni::jboolean getDebug(JNIEnv&);
+
+ jni::jboolean isFullyLoaded(JNIEnv&);
+
+ jni::jdouble getMetersPerPixelAtLatitude(JNIEnv&, jni::jdouble, jni::jdouble);
+
+ jni::Object<ProjectedMeters> projectedMetersForLatLng(JNIEnv&, jni::jdouble, jni::jdouble);
+
+ jni::Object<PointF> pixelForLatLng(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForProjectedMeters(JNIEnv&, jdouble, jdouble);
+
+ jni::Object<LatLng> latLngForPixel(JNIEnv&, jfloat, jfloat);
+
+ jni::Array<jlong> addPolylines(JNIEnv&, jni::Array<jni::Object<Polyline>>);
+
+ jni::Array<jlong> addPolygons(JNIEnv&, jni::Array<jni::Object<Polygon>>);
+
+ void updatePolyline(JNIEnv&, jlong, jni::Object<Polyline>);
+
+ void updatePolygon(JNIEnv&, jlong, jni::Object<Polygon>);
+
+ void removeAnnotations(JNIEnv&, jni::Array<jlong>);
+
+ void addAnnotationIcon(JNIEnv&, jni::String, jint, jint, jfloat, jni::Array<jbyte>);
+
+ jni::jdouble getTopOffsetPixelsForAnnotationSymbol(JNIEnv&, jni::String);
+
+ jni::jlong getTransitionDuration(JNIEnv&);
+
+ void setTransitionDuration(JNIEnv&, jni::jlong);
+
+ jni::jlong getTransitionDelay(JNIEnv&);
+
+ void setTransitionDelay(JNIEnv&, jni::jlong);
+
+ jni::Array<jlong> queryPointAnnotations(JNIEnv&, jni::Object<RectF>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Array<jni::Object<Feature>> queryRenderedFeaturesForBox(JNIEnv&, jni::jfloat, jni::jfloat, jni::jfloat, jni::jfloat, jni::Array<jni::String>);
+
+ jni::Array<jni::Object<Layer>> getLayers(JNIEnv&);
+
+ jni::Object<Layer> getLayer(JNIEnv&, jni::String);
+
+ void addLayer(JNIEnv&, jlong, jni::String);
+
+ void addLayerAbove(JNIEnv&, jlong, jni::String);
+
+ void addLayerAt(JNIEnv&, jni::jlong, jni::jint);
+
+ jni::Object<Layer> removeLayerById(JNIEnv&, jni::String);
+
+ jni::Object<Layer> removeLayerAt(JNIEnv&, jni::jint);
+
+ void removeLayer(JNIEnv&, jlong);
+
+ jni::Array<jni::Object<Source>> getSources(JNIEnv&);
+
+ jni::Object<Source> getSource(JNIEnv&, jni::String);
+
+ void addSource(JNIEnv&, jni::jlong);
+
+ jni::Object<Source> removeSourceById(JNIEnv&, jni::String);
+
+ void removeSource(JNIEnv&, jlong);
+
+ void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>);
+
+ void removeImage(JNIEnv&, jni::String);
protected:
+ // mbgl::Backend //
+
void activate() override;
void deactivate() override;
private:
+ void _initializeDisplay();
+
+ void _terminateDisplay();
+
+ void _initializeContext();
+
+ void _terminateContext();
+
+ void _createSurface(ANativeWindow*);
+
+ void _destroySurface();
+
EGLConfig chooseConfig(const EGLConfig configs[], EGLint numConfigs);
+ void updateViewBinding();
+ mbgl::Size getFramebufferSize() const;
+
+ void updateFps();
+
private:
+
JavaVM *vm = nullptr;
- JNIEnv *env = nullptr;
- jweak obj = nullptr;
+ jni::UniqueWeakObject<NativeMapView> javaPeer;
+
+ std::string styleUrl;
+ std::string apiKey;
ANativeWindow *window = nullptr;
+ EGLConfig config = nullptr;
+ EGLint format = -1;
+
EGLDisplay oldDisplay = EGL_NO_DISPLAY;
EGLSurface oldReadSurface = EGL_NO_SURFACE;
EGLSurface oldDrawSurface = EGL_NO_SURFACE;
@@ -75,15 +279,11 @@ private:
EGLSurface surface = EGL_NO_SURFACE;
EGLContext context = EGL_NO_CONTEXT;
- EGLConfig config = nullptr;
- EGLint format = -1;
- std::string styleUrl;
- std::string apiKey;
-
- bool firstTime = false;
+ float pixelRatio;
bool fpsEnabled = false;
bool snapshot = false;
+ bool firstRender = true;
double fps = 0.0;
int width = 0;
@@ -96,12 +296,12 @@ private:
size_t totalMemory = 0;
// Ensure these are initialised last
- std::unique_ptr<mbgl::DefaultFileSource> fileSource;
- mbgl::ThreadPool threadPool;
+ std::shared_ptr<mbgl::ThreadPool> threadPool;
std::unique_ptr<mbgl::Map> map;
mbgl::EdgeInsets insets;
unsigned active = 0;
};
-}
-}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp
new file mode 100644
index 0000000000..02871e7fdf
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.cpp
@@ -0,0 +1,164 @@
+#include "offline_manager.hpp"
+
+#include <mbgl/util/string.hpp>
+
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineManager //
+
+OfflineManager::OfflineManager(jni::JNIEnv& env, jni::Object<FileSource> jFileSource)
+ : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {
+}
+
+OfflineManager::~OfflineManager() {}
+
+void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) {
+ fileSource.setOfflineMapboxTileCountLimit(limit);
+}
+
+void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object<FileSource> jFileSource_, jni::Object<ListOfflineRegionsCallback> callback_) {
+ // list regions
+ fileSource.listOfflineRegions([
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object<ListOfflineRegionsCallback>(*callback), error);
+ } else if (regions) {
+ OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object<FileSource>(*jFileSource), jni::Object<ListOfflineRegionsCallback>(*callback), std::move(regions));
+ }
+ });
+}
+
+void OfflineManager::createOfflineRegion(jni::JNIEnv& env_,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition_,
+ jni::Array<jni::jbyte> metadata_,
+ jni::Object<CreateOfflineRegionCallback> callback_) {
+ // Convert
+
+ // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition
+ auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object<OfflineTilePyramidRegionDefinition>(*definition_));
+
+ mbgl::OfflineRegionMetadata metadata;
+ if (metadata_) {
+ metadata = OfflineRegion::metadata(env_, metadata_);
+ }
+
+ // Create region
+ fileSource.createOfflineRegion(definition, metadata, [
+ //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()),
+ jFileSource = std::shared_ptr<jni::jobject>(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegion> region) mutable {
+
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object<CreateOfflineRegionCallback>(*callback), error);
+ } else if (region) {
+ OfflineManager::CreateOfflineRegionCallback::onCreate(
+ *env,
+ jni::Object<FileSource>(*jFileSource),
+ jni::Object<CreateOfflineRegionCallback>(*callback), std::move(region)
+ );
+ }
+ });
+}
+
+jni::Class<OfflineManager> OfflineManager::javaClass;
+
+void OfflineManager::registerNative(jni::JNIEnv& env) {
+ OfflineManager::ListOfflineRegionsCallback::registerNative(env);
+ OfflineManager::CreateOfflineRegionCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineManager>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineManager>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineManager, JNIEnv&, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineManager::setOfflineMapboxTileCountLimit, "setOfflineMapboxTileCountLimit"),
+ METHOD(&OfflineManager::listOfflineRegions, "listOfflineRegions"),
+ METHOD(&OfflineManager::createOfflineRegion, "createOfflineRegion"));
+}
+
+// OfflineManager::ListOfflineRegionsCallback //
+
+void OfflineManager::ListOfflineRegionsCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineManager::ListOfflineRegionsCallback::onList(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback> callback,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
+ //Convert the regions to java peer objects
+ std::size_t index = 0;
+ auto jregions = jni::Array<jni::Object<OfflineRegion>>::New(env, regions->size(), OfflineRegion::javaClass);
+ for (auto& region : *regions) {
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(region));
+ jregions.Set(env, index, jregion);
+ jni::DeleteLocalRef(env, jregion);
+ index++;
+ }
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::Object<OfflineRegion>>)>(env, "onList");
+ callback.Call(env, method, jregions);
+ jni::DeleteLocalRef(env, jregions);
+}
+
+jni::Class<OfflineManager::ListOfflineRegionsCallback> OfflineManager::ListOfflineRegionsCallback::javaClass;
+
+void OfflineManager::ListOfflineRegionsCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::ListOfflineRegionsCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineManager::CreateOfflineRegionCallback //
+
+void OfflineManager::CreateOfflineRegionCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env,
+ jni::Object<FileSource> jFileSource,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback,
+ mbgl::optional<mbgl::OfflineRegion> region) {
+ //Convert the region to java peer object
+ auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegion>)>(env, "onCreate");
+ callback.Call(env, method, jregion);
+ jni::DeleteLocalRef(env, jregion);
+}
+
+jni::Class<OfflineManager::CreateOfflineRegionCallback> OfflineManager::CreateOfflineRegionCallback::javaClass;
+
+void OfflineManager::CreateOfflineRegionCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineManager::CreateOfflineRegionCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp
new file mode 100644
index 0000000000..9ae2714ca2
--- /dev/null
+++ b/platform/android/src/offline/offline_manager.hpp
@@ -0,0 +1,75 @@
+#pragma once
+
+
+#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+#include "offline_region.hpp"
+#include "offline_region_definition.hpp"
+
+
+namespace mbgl {
+namespace android {
+
+class OfflineManager {
+public:
+
+ class ListOfflineRegionsCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$ListOfflineRegionsCallback";}
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::ListOfflineRegionsCallback>, std::exception_ptr);
+
+ static void onList(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::ListOfflineRegionsCallback>,
+ mbgl::optional<std::vector<mbgl::OfflineRegion>>);
+
+ static jni::Class<OfflineManager::ListOfflineRegionsCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class CreateOfflineRegionCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager$CreateOfflineRegionCallback"; }
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineManager::CreateOfflineRegionCallback>, std::exception_ptr);
+
+ static void onCreate(jni::JNIEnv&,
+ jni::Object<FileSource>,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback>,
+ mbgl::optional<mbgl::OfflineRegion>);
+
+ static jni::Class<OfflineManager::CreateOfflineRegionCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineManager"; };
+
+ static jni::Class<OfflineManager> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ OfflineManager(jni::JNIEnv&, jni::Object<FileSource>);
+ ~OfflineManager();
+
+ void setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit);
+
+ void listOfflineRegions(jni::JNIEnv&, jni::Object<FileSource>, jni::Object<ListOfflineRegionsCallback> callback);
+
+ void createOfflineRegion(jni::JNIEnv&,
+ jni::Object<FileSource> jFileSource_,
+ jni::Object<OfflineRegionDefinition> definition,
+ jni::Array<jni::jbyte> metadata,
+ jni::Object<OfflineManager::CreateOfflineRegionCallback> callback);
+
+private:
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp
new file mode 100644
index 0000000000..856434d266
--- /dev/null
+++ b/platform/android/src/offline/offline_region.cpp
@@ -0,0 +1,308 @@
+#include "offline_region.hpp"
+
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
+
+#include "offline_region_definition.hpp"
+#include "offline_region_error.hpp"
+#include "offline_region_status.hpp"
+#include "../attach_env.hpp"
+#include "../jni/generic_global_ref_deleter.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegion //
+
+OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, jni::Object<FileSource> jFileSource)
+ : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)),
+ fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {}
+
+OfflineRegion::~OfflineRegion() {}
+
+void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, jni::Object<OfflineRegion::OfflineRegionObserver> callback) {
+
+ // Define the observer
+ class Observer : public mbgl::OfflineRegionObserver {
+ public:
+ Observer(jni::UniqueObject<OfflineRegion::OfflineRegionObserver>&& callback_)
+ //TODO add a generic deleter for jni::Object
+ : callback(callback_.release()->Get()) {
+ }
+
+ ~Observer() override {
+ android::UniqueEnv env = android::AttachEnv();
+ env->DeleteGlobalRef(Unwrap(*callback));
+ }
+
+ void statusChanged(mbgl::OfflineRegionStatus status) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Status object
+ auto jStatus = OfflineRegionStatus::New(*env, status);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<OfflineRegionStatus>)>(*env, "onStatusChanged");
+ callback.Call(*env, method, jStatus);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jStatus);
+ }
+
+ void responseError(mbgl::Response::Error error) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Error object
+ auto jError = OfflineRegionError::New(*env, error);
+
+ // Call
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::Object<mbgl::android::OfflineRegionError>)>(*env, "onError");
+ callback.Call(*env, method, jError);
+
+ // Delete references
+ jni::DeleteLocalRef(*env, jError);
+ }
+
+ void mapboxTileCountLimitExceeded(uint64_t limit) override {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ // Send limit
+ static auto method = OfflineRegion::OfflineRegionObserver::javaClass
+ .GetMethod<void (jni::jlong)>(*env, "mapboxTileCountLimitExceeded");
+ callback.Call(*env, method, jlong(limit));
+ }
+
+ jni::Object<OfflineRegion::OfflineRegionObserver> callback;
+ };
+
+ // Set the observer
+ fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(callback.NewGlobalRef(env_)));
+}
+
+void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) {
+ // State
+ mbgl::OfflineRegionDownloadState state;
+ switch (jState) {
+ case 0:
+ state = mbgl::OfflineRegionDownloadState::Inactive;
+ break;
+ case 1:
+ state = mbgl::OfflineRegionDownloadState::Active;
+ break;
+ default:
+ mbgl::Log::Error(mbgl::Event::JNI, "State can only be 0 (inactive) or 1 (active).");
+ return;
+ }
+
+ fileSource.setOfflineRegionDownloadState(*region, state);
+}
+
+void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object<OfflineRegionStatusCallback> callback_) {
+
+ fileSource.getOfflineRegionStatus(*region, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionStatus> status) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionStatusCallback::onError(*env, jni::Object<OfflineRegionStatusCallback>(*callback), error);
+ } else if (status) {
+ OfflineRegionStatusCallback::onStatus(*env, jni::Object<OfflineRegionStatusCallback>(*callback), std::move(status));
+ }
+ });
+}
+
+void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, jni::Object<OfflineRegionDeleteCallback> callback_) {
+ // Delete
+ fileSource.deleteOfflineRegion(std::move(*region), [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionDeleteCallback::onError(*env, jni::Object<OfflineRegionDeleteCallback>(*callback), error);
+ } else {
+ OfflineRegionDeleteCallback::onDelete(*env, jni::Object<OfflineRegionDeleteCallback>(*callback));
+ }
+ });
+}
+
+void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array<jni::jbyte> jMetadata, jni::Object<OfflineRegionUpdateMetadataCallback> callback_) {
+
+ // Convert
+ auto metadata = OfflineRegion::metadata(env_, jMetadata);
+
+ fileSource.updateOfflineMetadata(region->getID(), metadata, [
+ //Ensure the object is not gc'd in the meanwhile
+ callback = std::shared_ptr<jni::jobject>(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter())
+ ](std::exception_ptr error, mbgl::optional<mbgl::OfflineRegionMetadata> data) mutable {
+ // Reattach, the callback comes from a different thread
+ android::UniqueEnv env = android::AttachEnv();
+
+ if (error) {
+ OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), error);
+ } else if (data) {
+ OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object<OfflineRegionUpdateMetadataCallback>(*callback), std::move(data));
+ }
+ });
+}
+
+jni::Object<OfflineRegion> OfflineRegion::New(jni::JNIEnv& env, jni::Object<FileSource> jFileSource, mbgl::OfflineRegion region) {
+
+ // Definition
+ auto definition = jni::Object<OfflineRegionDefinition>(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition()));
+
+ // Metadata
+ auto metadata = OfflineRegion::metadata(env, region.getMetadata());
+
+ // Create region java object
+ static auto constructor = OfflineRegion::javaClass.GetConstructor<jni::jlong, jni::Object<FileSource>, jni::jlong, jni::Object<OfflineRegionDefinition>, jni::Array<jni::jbyte>>(env);
+ auto jregion = OfflineRegion::javaClass.New(env, constructor,
+ reinterpret_cast<jni::jlong>(new mbgl::OfflineRegion(std::move(region))), //Copy a region to the heap
+ jFileSource, jni::jlong(region.getID()), definition, metadata);
+
+ //Delete references
+ jni::DeleteLocalRef(env, definition);
+ jni::DeleteLocalRef(env, metadata);
+
+ return jregion;
+}
+
+jni::Array<jni::jbyte> OfflineRegion::metadata(jni::JNIEnv& env, mbgl::OfflineRegionMetadata metadata_) {
+ std::vector<jni::jbyte> convertedMetadata(metadata_.begin(), metadata_.end());
+ std::size_t length = static_cast<std::size_t>(convertedMetadata.size());
+ auto metadata = jni::Array<jni::jbyte>::New(env, length);
+ metadata.SetRegion<std::vector<jni::jbyte>>(env, 0, convertedMetadata);
+ return metadata;
+}
+
+mbgl::OfflineRegionMetadata OfflineRegion::metadata(jni::JNIEnv& env, jni::Array<jni::jbyte> metadata_) {
+ std::size_t length = metadata_.Length(env);
+ auto metadata_tmp = std::vector<jni::jbyte>();
+ metadata_tmp.resize(length);
+ metadata_.GetRegion<std::vector<jni::jbyte>>(env, 0, metadata_tmp);
+ auto metadata = std::vector<uint8_t>(metadata_tmp.begin(), metadata_tmp.end());
+ return metadata;
+}
+
+jni::Class<OfflineRegion> OfflineRegion::javaClass;
+
+void OfflineRegion::registerNative(jni::JNIEnv& env) {
+ OfflineRegion::OfflineRegionObserver::registerNative(env);
+ OfflineRegion::OfflineRegionStatusCallback::registerNative(env);
+ OfflineRegion::OfflineRegionDeleteCallback::registerNative(env);
+ OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(env);
+
+ javaClass = *jni::Class<OfflineRegion>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ jni::RegisterNativePeer<OfflineRegion>( env, javaClass, "nativePtr",
+ std::make_unique<OfflineRegion, JNIEnv&, jni::jlong, jni::Object<FileSource>>,
+ "initialize",
+ "finalize",
+ METHOD(&OfflineRegion::setOfflineRegionObserver, "setOfflineRegionObserver"),
+ METHOD(&OfflineRegion::setOfflineRegionDownloadState, "setOfflineRegionDownloadState"),
+ METHOD(&OfflineRegion::getOfflineRegionStatus, "getOfflineRegionStatus"),
+ METHOD(&OfflineRegion::deleteOfflineRegion, "deleteOfflineRegion"),
+ METHOD(&OfflineRegion::updateOfflineRegionMetadata, "updateOfflineRegionMetadata")
+ );
+}
+
+// OfflineRegionObserver //
+
+jni::Class<OfflineRegion::OfflineRegionObserver> OfflineRegion::OfflineRegionObserver::javaClass;
+
+void OfflineRegion::OfflineRegionObserver::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegion::OfflineRegionObserver>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineRegionStatusCallback //
+
+jni::Class<OfflineRegion::OfflineRegionStatusCallback> OfflineRegion::OfflineRegionStatusCallback::javaClass;
+
+void OfflineRegion::OfflineRegionStatusCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatusCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionStatusCallback::onStatus(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionStatusCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionStatus> status) {
+ //Convert to java peer object
+ auto jStatus = OfflineRegionStatus::New(env, std::move(*status));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Object<OfflineRegionStatus>)>(env, "onStatus");
+ callback.Call(env, method, jStatus);
+ jni::DeleteLocalRef(env, jStatus);
+}
+
+// OfflineRegionDeleteCallback //
+
+jni::Class<OfflineRegion::OfflineRegionDeleteCallback> OfflineRegion::OfflineRegionDeleteCallback::javaClass;
+
+void OfflineRegion::OfflineRegionDeleteCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDeleteCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionDeleteCallback::onDelete(jni::JNIEnv& env, jni::Object<OfflineRegion::OfflineRegionDeleteCallback> callback) {
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void ()>(env, "onDelete");
+ callback.Call(env, method);
+}
+
+// OfflineRegionUpdateMetadataCallback //
+
+jni::Class<OfflineRegion::OfflineRegionUpdateMetadataCallback> OfflineRegion::OfflineRegionUpdateMetadataCallback::javaClass;
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionUpdateMetadataCallback>::Find(env).NewGlobalRef(env).release();
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onError(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ std::exception_ptr error) {
+ static auto method = javaClass.GetMethod<void (jni::String)>(env, "onError");
+ std::string message = mbgl::util::toString(error);
+ callback.Call(env, method, jni::Make<jni::String>(env, message));
+}
+
+void OfflineRegion::OfflineRegionUpdateMetadataCallback::onUpdate(jni::JNIEnv& env,
+ jni::Object<OfflineRegion::OfflineRegionUpdateMetadataCallback> callback,
+ mbgl::optional<mbgl::OfflineRegionMetadata> metadata) {
+ //Convert to java peer object
+ auto jMetadata = OfflineRegion::metadata(env, std::move(*metadata));
+
+ // Trigger callback
+ static auto method = javaClass.GetMethod<void (jni::Array<jni::jbyte>)>(env, "onUpdate");
+ callback.Call(env, method, jMetadata);
+ jni::DeleteLocalRef(env, jMetadata);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp
new file mode 100644
index 0000000000..c05383a91a
--- /dev/null
+++ b/platform/android/src/offline/offline_region.hpp
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+#include "../file_source.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegion {
+public:
+ class OfflineRegionObserver {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionObserver"; };
+
+ static jni::Class<OfflineRegionObserver> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionStatusCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionStatusCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionStatusCallback>, std::exception_ptr);
+
+ static void onStatus(jni::JNIEnv&,
+ jni::Object<OfflineRegionStatusCallback>,
+ mbgl::optional<mbgl::OfflineRegionStatus>);
+
+ static jni::Class<OfflineRegionStatusCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionDeleteCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionDeleteCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>, std::exception_ptr);
+
+ static void onDelete(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ static jni::Class<OfflineRegionDeleteCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ class OfflineRegionUpdateMetadataCallback {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion$OfflineRegionUpdateMetadataCallback"; };
+
+ static void onError(jni::JNIEnv&, jni::Object<OfflineRegionUpdateMetadataCallback>, std::exception_ptr);
+
+ static void onUpdate(jni::JNIEnv&,
+ jni::Object<OfflineRegionUpdateMetadataCallback>,
+ mbgl::optional<mbgl::OfflineRegionMetadata>);
+
+ static jni::Class<OfflineRegionUpdateMetadataCallback> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+ };
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegion"; };
+
+ OfflineRegion(jni::JNIEnv&, jni::jlong, jni::Object<FileSource>);
+
+ ~OfflineRegion();
+
+ void setOfflineRegionObserver(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionObserver>);
+
+ void setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint);
+
+ void getOfflineRegionStatus(jni::JNIEnv&, jni::Object<OfflineRegion::OfflineRegionStatusCallback>);
+
+ void deleteOfflineRegion(jni::JNIEnv&, jni::Object<OfflineRegionDeleteCallback>);
+
+ void updateOfflineRegionMetadata(jni::JNIEnv&, jni::Array<jni::jbyte>, jni::Object<OfflineRegionUpdateMetadataCallback>);
+
+ static jni::Object<OfflineRegion> New(jni::JNIEnv&, jni::Object<FileSource>, mbgl::OfflineRegion);
+
+ static jni::Array<jni::jbyte> metadata(jni::JNIEnv&, mbgl::OfflineRegionMetadata);
+
+ static mbgl::OfflineRegionMetadata metadata(jni::JNIEnv&, jni::Array<jni::jbyte>);
+
+ static jni::Class<OfflineRegion> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+private:
+ std::unique_ptr<mbgl::OfflineRegion> region;
+ mbgl::DefaultFileSource& fileSource;
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp
new file mode 100644
index 0000000000..66a9bdf99d
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.cpp
@@ -0,0 +1,69 @@
+#include "offline_region_definition.hpp"
+
+#include "../geometry/lat_lng_bounds.hpp"
+
+namespace mbgl {
+namespace android {
+
+// OfflineRegionDefinition //
+
+jni::Class<OfflineRegionDefinition> OfflineRegionDefinition::javaClass;
+
+void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+// OfflineTilePyramidRegionDefinition //
+
+jni::Object<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) {
+
+ //Convert objects
+ auto styleURL = jni::Make<jni::String>(env, definition.styleURL);
+ auto bounds = LatLngBounds::New(env, definition.bounds);
+
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::Object<LatLngBounds>, jni::jdouble, jni::jdouble, jni::jfloat>(env);
+ auto jdefinition = javaClass.New(env, constructor, styleURL, bounds, definition.minZoom, definition.maxZoom, definition.pixelRatio);
+
+ //Delete References
+ jni::DeleteLocalRef(env, styleURL);
+ jni::DeleteLocalRef(env, bounds);
+
+ return jdefinition;
+}
+
+mbgl::OfflineTilePyramidRegionDefinition OfflineTilePyramidRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object<OfflineTilePyramidRegionDefinition> jDefinition) {
+ // Field references
+ static auto styleURLF = javaClass.GetField<jni::String>(env, "styleURL");
+ static auto boundsF = javaClass.GetField<jni::Object<LatLngBounds>>(env, "bounds");
+ static auto minZoomF = javaClass.GetField<jni::jdouble>(env, "minZoom");
+ static auto maxZoomF = javaClass.GetField<jni::jdouble>(env, "maxZoom");
+ static auto pixelRatioF = javaClass.GetField<jni::jfloat>(env, "pixelRatio");
+
+ // Get objects
+ auto jStyleURL = jDefinition.Get(env, styleURLF);
+ auto jBounds = jDefinition.Get(env, boundsF);
+
+ // Create definition
+ mbgl::OfflineTilePyramidRegionDefinition definition(
+ jni::Make<std::string>(env, jStyleURL),
+ LatLngBounds::getLatLngBounds(env, jBounds),
+ jDefinition.Get(env, minZoomF),
+ jDefinition.Get(env, maxZoomF),
+ jDefinition.Get(env, pixelRatioF)
+ );
+
+ // Delete references
+ jni::DeleteLocalRef(env, jStyleURL);
+ jni::DeleteLocalRef(env, jBounds);
+
+ return definition;
+}
+
+jni::Class<OfflineTilePyramidRegionDefinition> OfflineTilePyramidRegionDefinition::javaClass;
+
+void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineTilePyramidRegionDefinition>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp
new file mode 100644
index 0000000000..2ca82a4d96
--- /dev/null
+++ b/platform/android/src/offline/offline_region_definition.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionDefinition"; };
+
+ static jni::Class<OfflineRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; };
+
+ static jni::Object<OfflineTilePyramidRegionDefinition> New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition);
+
+ static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object<OfflineTilePyramidRegionDefinition>);
+
+ static jni::Class<OfflineTilePyramidRegionDefinition> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.cpp b/platform/android/src/offline/offline_region_error.cpp
new file mode 100644
index 0000000000..b0a19f934f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.cpp
@@ -0,0 +1,53 @@
+#include "offline_region_error.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionError> OfflineRegionError::New(jni::JNIEnv& env, mbgl::Response::Error error) {
+
+ // Handle the value of reason independently of the underlying int value
+ std::string reason;
+ switch(error.reason) {
+ case mbgl::Response::Error::Reason::Success:
+ reason = "REASON_SUCCESS";
+ break;
+ case mbgl::Response::Error::Reason::NotFound:
+ reason = "REASON_NOT_FOUND";
+ break;
+ case mbgl::Response::Error::Reason::Server:
+ reason = "REASON_SERVER";
+ break;
+ case mbgl::Response::Error::Reason::Connection:
+ reason = "REASON_CONNECTION";
+ break;
+ case mbgl::Response::Error::Reason::RateLimit:
+ reason = "REASON_RATE_LIMIT";
+ break;
+ case mbgl::Response::Error::Reason::Other:
+ reason = "REASON_OTHER";
+ break;
+ }
+
+ // Convert
+ auto jReason = jni::Make<jni::String>(env, reason);
+ auto jMessage = jni::Make<jni::String>(env, error.message);
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jni::String, jni::String>(env);
+ auto jError = javaClass.New(env, constructor, jReason, jMessage);
+
+ // Delete references
+ jni::DeleteLocalRef(env, jReason);
+ jni::DeleteLocalRef(env, jMessage);
+
+ return jError;
+}
+
+jni::Class<OfflineRegionError> OfflineRegionError::javaClass;
+
+void OfflineRegionError::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionError>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_error.hpp b/platform/android/src/offline/offline_region_error.hpp
new file mode 100644
index 0000000000..61efaca67e
--- /dev/null
+++ b/platform/android/src/offline/offline_region_error.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionError {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionError"; };
+
+ static jni::Object<OfflineRegionError> New(jni::JNIEnv&, mbgl::Response::Error);
+
+ static jni::Class<OfflineRegionError> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.cpp b/platform/android/src/offline/offline_region_status.cpp
new file mode 100644
index 0000000000..d0bbae124f
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.cpp
@@ -0,0 +1,39 @@
+#include "offline_region_status.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<OfflineRegionStatus> OfflineRegionStatus::New(jni::JNIEnv& env, mbgl::OfflineRegionStatus status) {
+
+ // Convert to jint
+ jint downloadState;
+ switch(status.downloadState) {
+ case mbgl::OfflineRegionDownloadState::Inactive:
+ downloadState = 0;
+ break;
+ case mbgl::OfflineRegionDownloadState::Active:
+ downloadState = 1;
+ break;
+ }
+
+ // Create java object
+ static auto constructor = javaClass.GetConstructor<jint, jlong, jlong, jlong, jlong, jlong, jboolean>(env);
+ return javaClass.New(env, constructor,
+ downloadState,
+ jlong(status.completedResourceCount),
+ jlong(status.completedResourceSize),
+ jlong(status.completedTileCount),
+ jlong(status.completedTileSize),
+ jlong(status.requiredResourceCount),
+ jboolean(status.requiredResourceCountIsPrecise)
+ );
+}
+
+jni::Class<OfflineRegionStatus> OfflineRegionStatus::javaClass;
+
+void OfflineRegionStatus::registerNative(jni::JNIEnv& env) {
+ javaClass = *jni::Class<OfflineRegionStatus>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/offline/offline_region_status.hpp b/platform/android/src/offline/offline_region_status.hpp
new file mode 100644
index 0000000000..b29a653655
--- /dev/null
+++ b/platform/android/src/offline/offline_region_status.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/storage/offline.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class OfflineRegionStatus {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineRegionStatus"; };
+
+ static jni::Object<OfflineRegionStatus> New(jni::JNIEnv&, mbgl::OfflineRegionStatus status);
+
+ static jni::Class<OfflineRegionStatus> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index de0ac91502..d9b88ab52b 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -4,7 +4,6 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
-#include <mbgl/util/feature.hpp>
#include <mbgl/util/optional.hpp>
#include <jni/jni.hpp>
@@ -45,7 +44,7 @@ inline optional<mbgl::android::Value> objectMember(const mbgl::android::Value& v
template <class Fn>
optional<Error> eachMember(const mbgl::android::Value&, Fn&&) {
- //TODO
+ // TODO
mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented");
return {};
}
@@ -82,7 +81,7 @@ inline optional<Value> toValue(const mbgl::android::Value& value) {
} else if (value.isString()) {
return { value.toString() };
} else if (value.isNumber()) {
- //Need to cast to a double here as the float is otherwise considered a bool...
+ // Need to cast to a double here as the float is otherwise considered a bool...
return { (double) value.toNumber() };
} else {
return {};
diff --git a/platform/android/src/style/conversion/function.hpp b/platform/android/src/style/conversion/function.hpp
index 26dd5c21fd..ad01a7afc2 100644
--- a/platform/android/src/style/conversion/function.hpp
+++ b/platform/android/src/style/conversion/function.hpp
@@ -4,51 +4,224 @@
#include "../../conversion/conversion.hpp"
#include "../../conversion/constant.hpp"
#include "types.hpp"
-#include "function.hpp"
+#include "../../java/lang.hpp"
+#include "../functions/stop.hpp"
+#include "../functions/categorical_stops.hpp"
+#include "../functions/exponential_stops.hpp"
+#include "../functions/identity_stops.hpp"
+#include "../functions/interval_stops.hpp"
#include <jni/jni.hpp>
#include <tuple>
-#include <vector>
+#include <map>
namespace mbgl {
namespace android {
namespace conversion {
-template <class T>
-inline jni::jobject* toFunctionStopJavaArray(jni::JNIEnv& env, std::vector<std::pair<float, T>> value) {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function$Stop")).release();
+/**
+ * Conversion from core composite value to java type
+ */
+class CategoricalValueEvaluator {
+public:
+
+ CategoricalValueEvaluator(jni::JNIEnv& _env) : env(_env) {}
+
+ template <class T>
+ jni::jobject* operator()(const T &value) const {
+ return *convert<jni::jobject*, T>(env, value);
+ }
+
+private:
+ jni::JNIEnv& env;
+};
+
+/**
+ * Conversion from core composite value to java type
+ */
+template <>
+struct Converter<jni::jobject*, mbgl::style::CategoricalValue> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CategoricalValue& value) const {
+ CategoricalValueEvaluator evaluator(env);
+ return apply_visitor(evaluator, value);
+ }
+};
+
+template <class I, class O>
+jni::Array<jni::Object<Stop>> toFunctionStopJavaArray(jni::JNIEnv& env, std::map<I, O> value) {
+
+ auto jarray = jni::Array<jni::Object<Stop>>::New(env, value.size(), Stop::javaClass);
+
+ size_t i = 0;
+ for (auto const& stop : value) {
+ jni::jobject* in = *convert<jni::jobject*, I>(env, stop.first);
+ jni::jobject* out = *convert<jni::jobject*, O>(env, stop.second);
+
+ auto jstop = Stop::New(env, jni::Object<>(in), jni::Object<>(out));
+ jarray.Set(env, i, jstop);
+
+ jni::DeleteLocalRef(env, in);
+ jni::DeleteLocalRef(env, out);
+ jni::DeleteLocalRef(env, jstop);
+
+ i++;
+ }
+
+ return jarray;
+}
+
+template <class I, class O>
+jni::Array<jni::Object<Stop>> toFunctionStopJavaArray(jni::JNIEnv& env, std::map<float, std::map<I, O>> value) {
+
+ auto jarray = jni::Array<jni::Object<Stop>>::New(env, value.size(), Stop::javaClass);
+
+ for (auto const& zoomLevelMap : value) {
+ size_t i = 0;
+ for (auto const& stop: zoomLevelMap.second) {
+ auto zoom = jni::Object<java::lang::Number>(*convert<jni::jobject*>(env, zoomLevelMap.first));
+ auto in = jni::Object<>(*convert<jni::jobject*, I>(env, stop.first));
+ auto out = jni::Object<>(*convert<jni::jobject*, O>(env, stop.second));
+ auto compositeValue = Stop::CompositeValue::New(env, zoom, in);
+
+ auto jstop = Stop::New(env, compositeValue, out);
+ jarray.Set(env, i, jstop);
+
+ jni::DeleteLocalRef(env, zoom);
+ jni::DeleteLocalRef(env, in);
+ jni::DeleteLocalRef(env, out);
+ jni::DeleteLocalRef(env, compositeValue);
+ jni::DeleteLocalRef(env, jstop);
+
+ i++;
+ }
+ }
+
+ return jarray;
+}
+
+template <class I, typename O>
+inline jni::jobject* convertCompositeStopsArray(jni::JNIEnv& env, std::map<float, std::map<I, O>> value) {
+ static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/stops/Stop")).release();
static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
jni::jarray<jni::jobject>& jarray = jni::NewObjectArray(env, value.size(), *javaClass);
- for(size_t i = 0; i < value.size(); i = i + 1) {
- jni::jobject* in = *convert<jni::jobject*, float>(env, value[i].first);
- jni::jobject* out = *convert<jni::jobject*, T>(env, value[i].second);
+ size_t i = 0;
+ for (auto const& stop : value) {
+ jni::jobject* in = *convert<jni::jobject*, I>(env, stop.first);
+ jni::jobject* out = *convert<jni::jobject*, O>(env, stop.second);
jni::SetObjectArrayElement(env, jarray, i, &jni::NewObject(env, *javaClass, *constructor, in, out));
+ i++;
+ jni::DeleteLocalRef(env, in);
+ jni::DeleteLocalRef(env, out);
}
return &jarray;
}
+/**
+ * Conversion from core function stops to Stops java subclasses
+ */
+template <class T>
+class StopsEvaluator {
+public:
+
+ StopsEvaluator(jni::JNIEnv& _env) : env(_env) {}
+
+ jni::jobject* operator()(const mbgl::style::CategoricalStops<T> &value) const {
+ return CategoricalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::CompositeCategoricalStops<T> &value) const {
+ return CategoricalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::ExponentialStops<T> &value) const {
+ return ExponentialStops::New(env, jni::Object<java::lang::Float>(*convert<jni::jobject*>(env, value.base)), toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::CompositeExponentialStops<T> &value) const {
+ return ExponentialStops::New(env, jni::Object<java::lang::Float>(*convert<jni::jobject*>(env, value.base)), toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::IdentityStops<T> &) const {
+ return IdentityStops::New(env).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::IntervalStops<T> &value) const {
+ return IntervalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+ jni::jobject* operator()(const mbgl::style::CompositeIntervalStops<T> &value) const {
+ return IntervalStops::New(env, toFunctionStopJavaArray(env, value.stops)).Get();
+ }
+
+private:
+ jni::JNIEnv& env;
+};
+
template <class T>
-struct Converter<jni::jobject*, mbgl::style::Function<T>> {
+struct Converter<jni::jobject*, mbgl::style::CameraFunction<T>> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CameraFunction<T>& value) const {
+ static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/CameraFunction")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>", "(Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V");
+
+ StopsEvaluator<T> evaluator(env);
+ jni::jobject* stops = apply_visitor(evaluator, value.stops);
+ jni::jobject* converted = &jni::NewObject(env, *clazz, *constructor, stops);
+
+ return { converted };
+ }
+};
+
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::SourceFunction<T>> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::SourceFunction<T>& value) const {
+ static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/SourceFunction")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V");
+
+ // Convert stops
+ StopsEvaluator<T> evaluator(env);
+ jni::jobject* stops = apply_visitor(evaluator, value.stops);
+
+ // Convert default value
+ jni::jobject* defaultValue = nullptr;
+ if (value.defaultValue) {
+ defaultValue = *convert<jni::jobject*>(env, *value.defaultValue);
+ }
+
+ return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make<jni::String>(env, value.property).Get(), stops) };
+ }
+};
+
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::CompositeFunction<T>> {
+
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::CompositeFunction<T>& value) const {
+ static jni::jclass* clazz = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/functions/CompositeFunction")).release();
+ static jni::jmethodID* constructor = &jni::GetMethodID(env, *clazz, "<init>",
+ "(Ljava/lang/Object;Ljava/lang/String;Lcom/mapbox/mapboxsdk/style/functions/stops/Stops;)V");
- Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::Function<T>& value) const {
- static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/mapbox/mapboxsdk/style/layers/Function")).release();
- static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "<init>", "([Lcom/mapbox/mapboxsdk/style/layers/Function$Stop;)V");
- static jni::jmethodID* withBase = &jni::GetMethodID(env, *javaClass, "withBase", "(F)Lcom/mapbox/mapboxsdk/style/layers/Function;");
+ // Convert stops
+ StopsEvaluator<T> evaluator(env);
+ jni::jobject* stops = apply_visitor(evaluator, value.stops);
- //Create object
- jni::jobject* jfunction = &jni::NewObject(env, *javaClass, *constructor, *toFunctionStopJavaArray(env, value.getStops()));
- //Set base
- jni::CallMethod<jni::jobject*>(env, jfunction, *withBase, value.getBase());
+ // Convert default value
+ jni::jobject* defaultValue = nullptr;
+ if (value.defaultValue) {
+ defaultValue = *convert<jni::jobject*>(env, *value.defaultValue);
+ }
- return {jfunction};
+ return { &jni::NewObject(env, *clazz, *constructor, defaultValue, jni::Make<jni::String>(env, value.property).Get(), stops) };
}
};
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/geojson.hpp b/platform/android/src/style/conversion/geojson.hpp
index 6bc48b3700..415d96f467 100644
--- a/platform/android/src/style/conversion/geojson.hpp
+++ b/platform/android/src/style/conversion/geojson.hpp
@@ -19,7 +19,7 @@ namespace conversion {
template <>
Result<GeoJSON> convertGeoJSON(const mbgl::android::Value& value) {
- //Value should be a string wrapped in an object
+ // Value should be a string wrapped in an object
mbgl::android::Value jsonValue = value.get("data");
if(value.isNull()) {
return Error { "no json data found" };
@@ -54,4 +54,4 @@ struct Converter<GeoJSON> {
} // namespace conversion
} // namespace style
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp
index 4121192f3f..a58cf975a7 100644
--- a/platform/android/src/style/conversion/property_value.hpp
+++ b/platform/android/src/style/conversion/property_value.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include "../../conversion/conversion.hpp"
#include "../../conversion/constant.hpp"
#include "types.hpp"
@@ -10,29 +11,65 @@ namespace mbgl {
namespace android {
namespace conversion {
+/**
+ * Conversion from core property value types to Java property value types
+ */
+template <typename T>
+class PropertyValueEvaluator {
+public:
+
+ PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {}
+
+ jni::jobject* operator()(const mbgl::style::Undefined) const {
+ return nullptr;
+ }
+
+ jni::jobject* operator()(const T &value) const {
+ Result<jni::jobject*> result = convert<jni::jobject*>(env, value);
+ return *result;
+ }
+
+ jni::jobject* operator()(const mbgl::style::CameraFunction<T> &value) const {
+ return *convert<jni::jobject*, mbgl::style::CameraFunction<T>>(env, value);
+ }
+
+ jni::jobject* operator()(const mbgl::style::SourceFunction<T> &value) const {
+ return *convert<jni::jobject*, mbgl::style::SourceFunction<T>>(env, value);
+ }
+
+ jni::jobject* operator()(const mbgl::style::CompositeFunction<T> &value) const {
+ return *convert<jni::jobject*, mbgl::style::CompositeFunction<T>>(env, value);
+ }
+
+private:
+ jni::JNIEnv& env;
+
+};
+
+/**
+ * Convert core property values to java
+ */
template <class T>
struct Converter<jni::jobject*, mbgl::style::PropertyValue<T>> {
Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue<T>& value) const {
+ PropertyValueEvaluator<T> evaluator(env);
+ return value.evaluate(evaluator);
+ }
+};
- if(value.isUndefined()) {
- //Return a nullptr representing a Java null value
- return {nullptr};
- } else if (value.isConstant()) {
- //Time to convert the constant value
- Result<jni::jobject*> result = convert<jni::jobject*, T>(env, value.asConstant());
- return {*result};
- //return converted;
- } else if (value.isFunction()) {
- //Must be a function than
- return convert<jni::jobject*, mbgl::style::Function<T>>(env, value.asFunction());
- } else {
- throw std::runtime_error("Unknown property value type");
- }
+/**
+ * Convert core data driven property values to java
+ */
+template <class T>
+struct Converter<jni::jobject*, mbgl::style::DataDrivenPropertyValue<T>> {
+ Result<jni::jobject*> operator()(jni::JNIEnv& env, const mbgl::style::DataDrivenPropertyValue<T>& value) const {
+ PropertyValueEvaluator<T> evaluator(env);
+ return value.evaluate(evaluator);
}
};
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp
index 1c433bb264..d9921e582e 100644
--- a/platform/android/src/style/conversion/types.hpp
+++ b/platform/android/src/style/conversion/types.hpp
@@ -95,4 +95,4 @@ struct Converter<jni::jobject*, mbgl::style::CirclePitchScaleType> {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types.hpp.ejs b/platform/android/src/style/conversion/types.hpp.ejs
index d248d42b72..3cd4764015 100644
--- a/platform/android/src/style/conversion/types.hpp.ejs
+++ b/platform/android/src/style/conversion/types.hpp.ejs
@@ -37,4 +37,4 @@ struct Converter<jni::jobject*, mbgl::style::<%- propertyNativeType(property) %>
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp
index 9f21a2fed9..e3108fdf5b 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp
+++ b/platform/android/src/style/conversion/types_string_values.hpp
@@ -10,7 +10,7 @@ namespace mbgl {
namespace android {
namespace conversion {
- //visibility
+ // visibility
inline std::string toString(mbgl::style::VisibilityType value) {
switch (value) {
case mbgl::style::VisibilityType::Visible:
@@ -24,7 +24,7 @@ namespace conversion {
}
}
- //line-cap
+ // line-cap
inline std::string toString(mbgl::style::LineCapType value) {
switch (value) {
case mbgl::style::LineCapType::Butt:
@@ -41,7 +41,7 @@ namespace conversion {
}
}
- //line-join
+ // line-join
inline std::string toString(mbgl::style::LineJoinType value) {
switch (value) {
case mbgl::style::LineJoinType::Bevel:
@@ -58,7 +58,7 @@ namespace conversion {
}
}
- //symbol-placement
+ // symbol-placement
inline std::string toString(mbgl::style::SymbolPlacementType value) {
switch (value) {
case mbgl::style::SymbolPlacementType::Point:
@@ -72,7 +72,7 @@ namespace conversion {
}
}
- //icon-rotation-alignment
+ // icon-rotation-alignment
inline std::string toString(mbgl::style::AlignmentType value) {
switch (value) {
case mbgl::style::AlignmentType::Map:
@@ -89,7 +89,7 @@ namespace conversion {
}
}
- //icon-text-fit
+ // icon-text-fit
inline std::string toString(mbgl::style::IconTextFitType value) {
switch (value) {
case mbgl::style::IconTextFitType::None:
@@ -109,7 +109,7 @@ namespace conversion {
}
}
- //text-justify
+ // text-justify
inline std::string toString(mbgl::style::TextJustifyType value) {
switch (value) {
case mbgl::style::TextJustifyType::Left:
@@ -126,7 +126,7 @@ namespace conversion {
}
}
- //text-anchor
+ // text-anchor
inline std::string toString(mbgl::style::TextAnchorType value) {
switch (value) {
case mbgl::style::TextAnchorType::Center:
@@ -161,7 +161,7 @@ namespace conversion {
}
}
- //text-transform
+ // text-transform
inline std::string toString(mbgl::style::TextTransformType value) {
switch (value) {
case mbgl::style::TextTransformType::None:
@@ -178,7 +178,7 @@ namespace conversion {
}
}
- //fill-translate-anchor
+ // fill-translate-anchor
inline std::string toString(mbgl::style::TranslateAnchorType value) {
switch (value) {
case mbgl::style::TranslateAnchorType::Map:
@@ -192,7 +192,7 @@ namespace conversion {
}
}
- //circle-pitch-scale
+ // circle-pitch-scale
inline std::string toString(mbgl::style::CirclePitchScaleType value) {
switch (value) {
case mbgl::style::CirclePitchScaleType::Map:
@@ -209,4 +209,4 @@ namespace conversion {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/types_string_values.hpp.ejs b/platform/android/src/style/conversion/types_string_values.hpp.ejs
index c1646baa1a..bf52919741 100644
--- a/platform/android/src/style/conversion/types_string_values.hpp.ejs
+++ b/platform/android/src/style/conversion/types_string_values.hpp.ejs
@@ -13,7 +13,7 @@ namespace mbgl {
namespace android {
namespace conversion {
- //visibility
+ // visibility
inline std::string toString(mbgl::style::VisibilityType value) {
switch (value) {
case mbgl::style::VisibilityType::Visible:
@@ -28,7 +28,7 @@ namespace conversion {
}
<% for (const property of properties) { -%>
- //<%- property.name %>
+ // <%- property.name %>
inline std::string toString(mbgl::style::<%- propertyNativeType(property) %> value) {
switch (value) {
<% for (const value in property.values) { -%>
@@ -45,4 +45,4 @@ namespace conversion {
} // namespace conversion
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp
index c1801f56d0..4e502324d0 100644
--- a/platform/android/src/style/conversion/url_or_tileset.hpp
+++ b/platform/android/src/style/conversion/url_or_tileset.hpp
@@ -35,4 +35,4 @@ struct Converter<variant<std::string, Tileset>> {
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/functions/categorical_stops.cpp b/platform/android/src/style/functions/categorical_stops.cpp
new file mode 100644
index 0000000000..2aff9730a7
--- /dev/null
+++ b/platform/android/src/style/functions/categorical_stops.cpp
@@ -0,0 +1,18 @@
+#include "categorical_stops.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<CategoricalStops> CategoricalStops::New(jni::JNIEnv& env, jni::Array<jni::Object<Stop>> stops) {
+ static auto constructor = CategoricalStops::javaClass.GetConstructor<jni::Array<jni::Object<Stop>>>(env);
+ return CategoricalStops::javaClass.New(env, constructor, stops);
+}
+
+jni::Class<CategoricalStops> CategoricalStops::javaClass;
+
+void CategoricalStops::registerNative(jni::JNIEnv& env) {
+ CategoricalStops::javaClass = *jni::Class<CategoricalStops>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/categorical_stops.hpp b/platform/android/src/style/functions/categorical_stops.hpp
new file mode 100644
index 0000000000..a198c8d5c9
--- /dev/null
+++ b/platform/android/src/style/functions/categorical_stops.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "stop.hpp"
+
+namespace mbgl {
+namespace android {
+
+class CategoricalStops : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/CategoricalStops"; };
+
+ static jni::Object<CategoricalStops> New(jni::JNIEnv&, jni::Array<jni::Object<Stop>>);
+
+ static jni::Class<CategoricalStops> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/exponential_stops.cpp b/platform/android/src/style/functions/exponential_stops.cpp
new file mode 100644
index 0000000000..6390a0ec35
--- /dev/null
+++ b/platform/android/src/style/functions/exponential_stops.cpp
@@ -0,0 +1,18 @@
+#include "exponential_stops.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<ExponentialStops> ExponentialStops::New(jni::JNIEnv& env, jni::Object<java::lang::Float> base, jni::Array<jni::Object<Stop>> stops) {
+ static auto constructor = ExponentialStops::javaClass.GetConstructor<jni::Object<java::lang::Float>, jni::Array<jni::Object<Stop>>>(env);
+ return ExponentialStops::javaClass.New(env, constructor, base, stops);
+}
+
+jni::Class<ExponentialStops> ExponentialStops::javaClass;
+
+void ExponentialStops::registerNative(jni::JNIEnv& env) {
+ ExponentialStops::javaClass = *jni::Class<ExponentialStops>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/exponential_stops.hpp b/platform/android/src/style/functions/exponential_stops.hpp
new file mode 100644
index 0000000000..391d723cef
--- /dev/null
+++ b/platform/android/src/style/functions/exponential_stops.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "../../java/lang.hpp"
+#include "stop.hpp"
+
+namespace mbgl {
+namespace android {
+
+class ExponentialStops : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/ExponentialStops"; };
+
+ static jni::Object<ExponentialStops> New(jni::JNIEnv&, jni::Object<java::lang::Float>, jni::Array<jni::Object<Stop>>);
+
+ static jni::Class<ExponentialStops> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/identity_stops.cpp b/platform/android/src/style/functions/identity_stops.cpp
new file mode 100644
index 0000000000..239b0ddb88
--- /dev/null
+++ b/platform/android/src/style/functions/identity_stops.cpp
@@ -0,0 +1,18 @@
+#include "identity_stops.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<IdentityStops> IdentityStops::New(jni::JNIEnv& env) {
+ static auto constructor = IdentityStops::javaClass.GetConstructor<>(env);
+ return IdentityStops::javaClass.New(env, constructor);
+}
+
+jni::Class<IdentityStops> IdentityStops::javaClass;
+
+void IdentityStops::registerNative(jni::JNIEnv& env) {
+ IdentityStops::javaClass = *jni::Class<IdentityStops>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/identity_stops.hpp b/platform/android/src/style/functions/identity_stops.hpp
new file mode 100644
index 0000000000..150b2135f0
--- /dev/null
+++ b/platform/android/src/style/functions/identity_stops.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class IdentityStops : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/IdentityStops"; };
+
+ static jni::Object<IdentityStops> New(jni::JNIEnv&);
+
+ static jni::Class<IdentityStops> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/interval_stops.cpp b/platform/android/src/style/functions/interval_stops.cpp
new file mode 100644
index 0000000000..c3d9b6513f
--- /dev/null
+++ b/platform/android/src/style/functions/interval_stops.cpp
@@ -0,0 +1,18 @@
+#include "interval_stops.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<IntervalStops> IntervalStops::New(jni::JNIEnv& env, jni::Array<jni::Object<Stop>> stops) {
+ static auto constructor = IntervalStops::javaClass.GetConstructor<jni::Array<jni::Object<Stop>>>(env);
+ return IntervalStops::javaClass.New(env, constructor, stops);
+}
+
+jni::Class<IntervalStops> IntervalStops::javaClass;
+
+void IntervalStops::registerNative(jni::JNIEnv& env) {
+ IntervalStops::javaClass = *jni::Class<IntervalStops>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/interval_stops.hpp b/platform/android/src/style/functions/interval_stops.hpp
new file mode 100644
index 0000000000..e3f75159cf
--- /dev/null
+++ b/platform/android/src/style/functions/interval_stops.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "stop.hpp"
+
+namespace mbgl {
+namespace android {
+
+class IntervalStops : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/IntervalStops"; };
+
+ static jni::Object<IntervalStops> New(jni::JNIEnv&, jni::Array<jni::Object<Stop>>);
+
+ static jni::Class<IntervalStops> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/stop.cpp b/platform/android/src/style/functions/stop.cpp
new file mode 100644
index 0000000000..f9ed4b7368
--- /dev/null
+++ b/platform/android/src/style/functions/stop.cpp
@@ -0,0 +1,21 @@
+#include "interval_stops.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<Stop::CompositeValue> Stop::CompositeValue::New(jni::JNIEnv& env, jni::Object<java::lang::Number> zoom, jni::Object<> value) {
+ static auto constructor = Stop::CompositeValue::javaClass.GetConstructor<jni::Object<java::lang::Number>, jni::Object<>>(env);
+ return Stop::CompositeValue::javaClass.New(env, constructor, zoom, value);
+}
+
+jni::Class<Stop> Stop::javaClass;
+
+jni::Class<Stop::CompositeValue> Stop::CompositeValue::javaClass;
+
+void Stop::registerNative(jni::JNIEnv& env) {
+ Stop::javaClass = *jni::Class<Stop>::Find(env).NewGlobalRef(env).release();
+ Stop::CompositeValue::javaClass = *jni::Class<Stop::CompositeValue>::Find(env).NewGlobalRef(env).release();
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/functions/stop.hpp b/platform/android/src/style/functions/stop.hpp
new file mode 100644
index 0000000000..7c697db65d
--- /dev/null
+++ b/platform/android/src/style/functions/stop.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <jni/jni.hpp>
+
+#include "../../java/lang.hpp"
+
+namespace mbgl {
+namespace android {
+
+class Stop : private mbgl::util::noncopyable {
+public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/Stop"; };
+
+ template<class I, class O>
+ static jni::Object<Stop> New(jni::JNIEnv& env, jni::Object<I> in, jni::Object<O> out) {
+ static auto constructor = Stop::javaClass.GetConstructor<jni::Object<>, jni::Object<>>(env);
+ return Stop::javaClass.New(env, constructor, (jni::Object<>) in, (jni::Object<>) out);
+ }
+
+ static jni::Class<Stop> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ class CompositeValue : private mbgl::util::noncopyable {
+ public:
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/functions/stops/Stop$CompositeValue"; };
+
+ static jni::Object<Stop::CompositeValue> New(jni::JNIEnv&, jni::Object<java::lang::Number>, jni::Object<>);
+
+ static jni::Class<Stop::CompositeValue> javaClass;
+ };
+};
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/background_layer.cpp b/platform/android/src/style/layers/background_layer.cpp
index 021ac947ad..9915f3894e 100644
--- a/platform/android/src/style/layers/background_layer.cpp
+++ b/platform/android/src/style/layers/background_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
BackgroundLayer::BackgroundLayer(jni::JNIEnv& env, jni::String layerId)
: Layer(env, std::make_unique<mbgl::style::BackgroundLayer>(jni::Make<std::string>(env, layerId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
BackgroundLayer::BackgroundLayer(mbgl::Map& map, mbgl::style::BackgroundLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ BackgroundLayer::BackgroundLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::BackgroundLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
BackgroundLayer::~BackgroundLayer() = default;
// Property getters
@@ -47,12 +60,12 @@ namespace android {
}
void BackgroundLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
BackgroundLayer::javaClass = *jni::Class<BackgroundLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<BackgroundLayer>(
env, BackgroundLayer::javaClass, "nativePtr",
std::make_unique<BackgroundLayer, JNIEnv&, jni::String>,
diff --git a/platform/android/src/style/layers/background_layer.hpp b/platform/android/src/style/layers/background_layer.hpp
index bd62c024f4..2fdc948892 100644
--- a/platform/android/src/style/layers/background_layer.hpp
+++ b/platform/android/src/style/layers/background_layer.hpp
@@ -22,6 +22,8 @@ public:
BackgroundLayer(mbgl::Map&, mbgl::style::BackgroundLayer&);
+ BackgroundLayer(mbgl::Map&, std::unique_ptr<mbgl::style::BackgroundLayer>);
+
~BackgroundLayer();
// Property getters
diff --git a/platform/android/src/style/layers/circle_layer.cpp b/platform/android/src/style/layers/circle_layer.cpp
index 4a6ba95d31..948c397829 100644
--- a/platform/android/src/style/layers/circle_layer.cpp
+++ b/platform/android/src/style/layers/circle_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
CircleLayer::CircleLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::CircleLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
CircleLayer::CircleLayer(mbgl::Map& map, mbgl::style::CircleLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ CircleLayer::CircleLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::CircleLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
CircleLayer::~CircleLayer() = default;
// Property getters
@@ -89,12 +102,12 @@ namespace android {
}
void CircleLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
CircleLayer::javaClass = *jni::Class<CircleLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<CircleLayer>(
env, CircleLayer::javaClass, "nativePtr",
std::make_unique<CircleLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/circle_layer.hpp b/platform/android/src/style/layers/circle_layer.hpp
index d45984f23b..ee988d7c57 100644
--- a/platform/android/src/style/layers/circle_layer.hpp
+++ b/platform/android/src/style/layers/circle_layer.hpp
@@ -22,6 +22,8 @@ public:
CircleLayer(mbgl::Map&, mbgl::style::CircleLayer&);
+ CircleLayer(mbgl::Map&, std::unique_ptr<mbgl::style::CircleLayer>);
+
~CircleLayer();
// Property getters
diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp
index d5d330a019..9bdc308d85 100644
--- a/platform/android/src/style/layers/custom_layer.cpp
+++ b/platform/android/src/style/layers/custom_layer.cpp
@@ -40,12 +40,12 @@ namespace android {
}
void CustomLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
CustomLayer::javaClass = *jni::Class<CustomLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<CustomLayer>(
env, CustomLayer::javaClass, "nativePtr",
std::make_unique<CustomLayer, JNIEnv&, jni::String, jni::jlong, jni::jlong, jni::jlong, jni::jlong>,
diff --git a/platform/android/src/style/layers/fill_layer.cpp b/platform/android/src/style/layers/fill_layer.cpp
index 84d47b6afe..fc1dfccfcc 100644
--- a/platform/android/src/style/layers/fill_layer.cpp
+++ b/platform/android/src/style/layers/fill_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
FillLayer::FillLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::FillLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
FillLayer::FillLayer(mbgl::Map& map, mbgl::style::FillLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ FillLayer::FillLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::FillLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
FillLayer::~FillLayer() = default;
// Property getters
@@ -71,12 +84,12 @@ namespace android {
}
void FillLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
FillLayer::javaClass = *jni::Class<FillLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<FillLayer>(
env, FillLayer::javaClass, "nativePtr",
std::make_unique<FillLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/fill_layer.hpp b/platform/android/src/style/layers/fill_layer.hpp
index 7609a5742f..f43c263ab8 100644
--- a/platform/android/src/style/layers/fill_layer.hpp
+++ b/platform/android/src/style/layers/fill_layer.hpp
@@ -22,6 +22,8 @@ public:
FillLayer(mbgl::Map&, mbgl::style::FillLayer&);
+ FillLayer(mbgl::Map&, std::unique_ptr<mbgl::style::FillLayer>);
+
~FillLayer();
// Property getters
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index c0c57c839d..dbf71fd2af 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -5,12 +5,12 @@
#include <mbgl/util/logging.hpp>
-//Java -> C++ conversion
+// Java -> C++ conversion
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
-//C++ -> Java conversion
+// C++ -> Java conversion
#include "../conversion/property_value.hpp"
#include <string>
@@ -26,22 +26,35 @@ namespace android {
, layer(*ownedLayer) {
}
+ /**
+ * Takes a non-owning reference. For lookup methods
+ */
Layer::Layer(mbgl::Map& coreMap, mbgl::style::Layer& coreLayer) : layer(coreLayer) , map(&coreMap) {
}
+ /**
+ * Takes a owning reference. Ownership is transfered to this peer, eg after removing
+ * from the map
+ */
+ Layer::Layer(mbgl::Map& coreMap, std::unique_ptr<mbgl::style::Layer> coreLayer)
+ : ownedLayer(std::move(coreLayer))
+ , layer(*ownedLayer)
+ , map(&coreMap) {
+ }
+
Layer::~Layer() {
}
void Layer::addToMap(mbgl::Map& _map, mbgl::optional<std::string> before) {
- //Check to see if we own the layer first
+ // Check to see if we own the layer first
if (!ownedLayer) {
throw std::runtime_error("Cannot add layer twice");
}
- //Add layer to map
+ // Add layer to map
_map.addLayer(releaseCoreLayer(), before);
- //Save pointer to the map
+ // Save pointer to the map
this->map = &_map;
}
@@ -65,7 +78,7 @@ namespace android {
void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
Value value(env, jvalue);
- //Convert and set property
+ // Convert and set property
optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make<std::string>(env, jname), value);
if (error) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
@@ -76,7 +89,7 @@ namespace android {
void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) {
Value value(env, jvalue);
- //Convert and set property
+ // Convert and set property
optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value, mbgl::optional<std::string>());
if (error) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
@@ -153,12 +166,12 @@ namespace android {
jni::Class<Layer> Layer::javaClass;
void Layer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
Layer::javaClass = *jni::Class<Layer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<Layer>(env, Layer::javaClass, "nativePtr",
METHOD(&Layer::getId, "nativeGetId"),
METHOD(&Layer::setLayoutProperty, "nativeSetLayoutProperty"),
@@ -174,5 +187,5 @@ namespace android {
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.cpp.ejs b/platform/android/src/style/layers/layer.cpp.ejs
index 500c76ea7a..5da397d77d 100644
--- a/platform/android/src/style/layers/layer.cpp.ejs
+++ b/platform/android/src/style/layers/layer.cpp.ejs
@@ -14,18 +14,34 @@ namespace mbgl {
namespace android {
<% if (type === 'background') { -%>
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId))) {
<% } else { -%>
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::<%- camelize(type) %>Layer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
<% } -%>
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
<%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, mbgl::style::<%- camelize(type) %>Layer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ <%- camelize(type) %>Layer::<%- camelize(type) %>Layer(mbgl::Map& map, std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
<%- camelize(type) %>Layer::~<%- camelize(type) %>Layer() = default;
// Property getters
@@ -46,12 +62,12 @@ namespace android {
}
void <%- camelize(type) %>Layer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
<%- camelize(type) %>Layer::javaClass = *jni::Class<<%- camelize(type) %>Layer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<<%- camelize(type) %>Layer>(
env, <%- camelize(type) %>Layer::javaClass, "nativePtr",
<% if (type === 'background') { -%>
diff --git a/platform/android/src/style/layers/layer.hpp b/platform/android/src/style/layers/layer.hpp
index f3cd073552..deea7a6613 100644
--- a/platform/android/src/style/layers/layer.hpp
+++ b/platform/android/src/style/layers/layer.hpp
@@ -21,11 +21,16 @@ public:
static void registerNative(jni::JNIEnv&);
/*
- * Called when a Java object is created on the c++ side
+ * Called when a non-owning peer object is created on the c++ side
*/
Layer(mbgl::Map&, mbgl::style::Layer&);
/*
+ * Called when a owning peer object is created on the c++ side
+ */
+ Layer(mbgl::Map&, std::unique_ptr<mbgl::style::Layer>);
+
+ /*
* Called when a Java object was created from the jvm side
*/
Layer(jni::JNIEnv&, std::unique_ptr<mbgl::style::Layer>);
@@ -49,7 +54,7 @@ public:
void setPaintProperty(jni::JNIEnv&, jni::String, jni::Object<> value);
- //Zoom
+ // Zoom
jni::jfloat getMinZoom(jni::JNIEnv&);
@@ -65,28 +70,24 @@ public:
void setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer);
- //Property getters
+ // Property getters
jni::Object<jni::ObjectTag> getVisibility(jni::JNIEnv&);
protected:
- //Release the owned view and return it
+ // Release the owned view and return it
std::unique_ptr<mbgl::style::Layer> releaseCoreLayer();
- //Owned layer is set when creating a new layer, before adding it to the map
+ // Owned layer is set when creating a new layer, before adding it to the map
std::unique_ptr<mbgl::style::Layer> ownedLayer;
- //Raw reference to the layer
+ // Raw reference to the layer
mbgl::style::Layer& layer;
- //Map is set when the layer is retrieved or after adding to the map
+ // Map is set when the layer is retrieved or after adding to the map
mbgl::Map* map;
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layer.hpp.ejs b/platform/android/src/style/layers/layer.hpp.ejs
index 3d715746ff..102efd2d4d 100644
--- a/platform/android/src/style/layers/layer.hpp.ejs
+++ b/platform/android/src/style/layers/layer.hpp.ejs
@@ -30,6 +30,8 @@ public:
<%- camelize(type) %>Layer(mbgl::Map&, mbgl::style::<%- camelize(type) %>Layer&);
+ <%- camelize(type) %>Layer(mbgl::Map&, std::unique_ptr<mbgl::style::<%- camelize(type) %>Layer>);
+
~<%- camelize(type) %>Layer();
// Property getters
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
index 57dbf6f4b1..5c6ee1ae8f 100644
--- a/platform/android/src/style/layers/layers.cpp
+++ b/platform/android/src/style/layers/layers.cpp
@@ -1,5 +1,6 @@
#include "layers.hpp"
+#include <mbgl/style/layer.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -10,55 +11,86 @@
#include "background_layer.hpp"
#include "circle_layer.hpp"
+#include "custom_layer.hpp"
#include "fill_layer.hpp"
#include "line_layer.hpp"
#include "raster_layer.hpp"
#include "symbol_layer.hpp"
-#include "custom_layer.hpp"
+#include "unknown_layer.hpp"
namespace mbgl {
namespace android {
-Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
- Layer* layer;
+static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
if (coreLayer.is<mbgl::style::BackgroundLayer>()) {
- layer = new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
+ return new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
} else if (coreLayer.is<mbgl::style::CircleLayer>()) {
- layer = new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
+ return new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
} else if (coreLayer.is<mbgl::style::FillLayer>()) {
- layer = new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
+ return new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
} else if (coreLayer.is<mbgl::style::LineLayer>()) {
- layer = new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
+ return new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
} else if (coreLayer.is<mbgl::style::RasterLayer>()) {
- layer = new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
+ return new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
} else if (coreLayer.is<mbgl::style::SymbolLayer>()) {
- layer = new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
+ return new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
} else if (coreLayer.is<mbgl::style::CustomLayer>()) {
- layer = new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
+ return new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
} else {
- throw new std::runtime_error("Layer type not implemented");
+ return new UnknownLayer(map, coreLayer);
}
+}
- return layer;
+template <class LayerType, class PeerType>
+static PeerType* createPeer(Map& map, std::unique_ptr<mbgl::style::Layer> layer) {
+ return new PeerType(map, std::move(std::unique_ptr<LayerType>(layer.release()->as<LayerType>())));
+}
+
+static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ if (coreLayer->is<style::BackgroundLayer>()) {
+ return createPeer<style::BackgroundLayer, BackgroundLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::CircleLayer>()) {
+ return createPeer<style::CircleLayer, CircleLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::FillLayer>()) {
+ return createPeer<style::FillLayer, FillLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::LineLayer>()) {
+ return createPeer<style::LineLayer, LineLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::RasterLayer>()) {
+ return createPeer<style::RasterLayer, RasterLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<style::SymbolLayer>()) {
+ return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
+ } else if (coreLayer->is<mbgl::style::CustomLayer>()) {
+ return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
+ } else {
+ return new UnknownLayer(map, std::move(coreLayer));
+ }
}
-jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, Map& map, style::Layer& coreLayer) {
std::unique_ptr<Layer> peerLayer = std::unique_ptr<Layer>(initializeLayerPeer(map, coreLayer));
jni::jobject* result = peerLayer->createJavaPeer(env);
peerLayer.release();
return result;
}
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ std::unique_ptr<Layer> peerLayer = std::unique_ptr<Layer>(initializeLayerPeer(map, std::move(coreLayer)));
+ jni::jobject* result = peerLayer->createJavaPeer(env);
+ peerLayer.release();
+ return result;
+}
+
void registerNativeLayers(jni::JNIEnv& env) {
Layer::registerNative(env);
BackgroundLayer::registerNative(env);
CircleLayer::registerNative(env);
+ CustomLayer::registerNative(env);
FillLayer::registerNative(env);
LineLayer::registerNative(env);
RasterLayer::registerNative(env);
SymbolLayer::registerNative(env);
- CustomLayer::registerNative(env);
+ UnknownLayer::registerNative(env);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/layers.hpp b/platform/android/src/style/layers/layers.hpp
index 0c979ec2cf..75863a324a 100644
--- a/platform/android/src/style/layers/layers.hpp
+++ b/platform/android/src/style/layers/layers.hpp
@@ -10,11 +10,17 @@
namespace mbgl {
namespace android {
-mbgl::android::Layer* initializeLayerPeer(mbgl::Map&, mbgl::style::Layer&);
-
+/**
+ * Create a non-owning peer
+ */
jni::jobject* createJavaLayerPeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Layer&);
+/**
+ * Create an owning peer
+ */
+jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, mbgl::Map& map, std::unique_ptr<mbgl::style::Layer>);
+
void registerNativeLayers(jni::JNIEnv&);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/layers/line_layer.cpp b/platform/android/src/style/layers/line_layer.cpp
index 2dce8b618a..1a3a666a7b 100644
--- a/platform/android/src/style/layers/line_layer.cpp
+++ b/platform/android/src/style/layers/line_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
LineLayer::LineLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::LineLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
LineLayer::LineLayer(mbgl::Map& map, mbgl::style::LineLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ LineLayer::LineLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::LineLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
LineLayer::~LineLayer() = default;
// Property getters
@@ -113,12 +126,12 @@ namespace android {
}
void LineLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
LineLayer::javaClass = *jni::Class<LineLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<LineLayer>(
env, LineLayer::javaClass, "nativePtr",
std::make_unique<LineLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/line_layer.hpp b/platform/android/src/style/layers/line_layer.hpp
index e2fc93329e..a79c8b9021 100644
--- a/platform/android/src/style/layers/line_layer.hpp
+++ b/platform/android/src/style/layers/line_layer.hpp
@@ -22,6 +22,8 @@ public:
LineLayer(mbgl::Map&, mbgl::style::LineLayer&);
+ LineLayer(mbgl::Map&, std::unique_ptr<mbgl::style::LineLayer>);
+
~LineLayer();
// Property getters
diff --git a/platform/android/src/style/layers/raster_layer.cpp b/platform/android/src/style/layers/raster_layer.cpp
index 25b26155ae..8a324b88f2 100644
--- a/platform/android/src/style/layers/raster_layer.cpp
+++ b/platform/android/src/style/layers/raster_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
RasterLayer::RasterLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::RasterLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
RasterLayer::RasterLayer(mbgl::Map& map, mbgl::style::RasterLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ RasterLayer::RasterLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::RasterLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
RasterLayer::~RasterLayer() = default;
// Property getters
@@ -71,12 +84,12 @@ namespace android {
}
void RasterLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
RasterLayer::javaClass = *jni::Class<RasterLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<RasterLayer>(
env, RasterLayer::javaClass, "nativePtr",
std::make_unique<RasterLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/raster_layer.hpp b/platform/android/src/style/layers/raster_layer.hpp
index 3cc2d96dde..2f5d4f6fcd 100644
--- a/platform/android/src/style/layers/raster_layer.hpp
+++ b/platform/android/src/style/layers/raster_layer.hpp
@@ -22,6 +22,8 @@ public:
RasterLayer(mbgl::Map&, mbgl::style::RasterLayer&);
+ RasterLayer(mbgl::Map&, std::unique_ptr<mbgl::style::RasterLayer>);
+
~RasterLayer();
// Property getters
diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp
index 9318d42d5b..e42eeb4c77 100644
--- a/platform/android/src/style/layers/symbol_layer.cpp
+++ b/platform/android/src/style/layers/symbol_layer.cpp
@@ -9,14 +9,27 @@
namespace mbgl {
namespace android {
+ /**
+ * Creates an owning peer object (for layers not attached to the map) from the JVM side
+ */
SymbolLayer::SymbolLayer(jni::JNIEnv& env, jni::String layerId, jni::String sourceId)
: Layer(env, std::make_unique<mbgl::style::SymbolLayer>(jni::Make<std::string>(env, layerId), jni::Make<std::string>(env, sourceId))) {
}
+ /**
+ * Creates a non-owning peer object (for layers currently attached to the map)
+ */
SymbolLayer::SymbolLayer(mbgl::Map& map, mbgl::style::SymbolLayer& coreLayer)
: Layer(map, coreLayer) {
}
+ /**
+ * Creates an owning peer object (for layers not attached to the map)
+ */
+ SymbolLayer::SymbolLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::SymbolLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
SymbolLayer::~SymbolLayer() = default;
// Property getters
@@ -317,12 +330,12 @@ namespace android {
}
void SymbolLayer::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
SymbolLayer::javaClass = *jni::Class<SymbolLayer>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<SymbolLayer>(
env, SymbolLayer::javaClass, "nativePtr",
std::make_unique<SymbolLayer, JNIEnv&, jni::String, jni::String>,
diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp
index 1048b01b14..98ce5572e9 100644
--- a/platform/android/src/style/layers/symbol_layer.hpp
+++ b/platform/android/src/style/layers/symbol_layer.hpp
@@ -22,6 +22,8 @@ public:
SymbolLayer(mbgl::Map&, mbgl::style::SymbolLayer&);
+ SymbolLayer(mbgl::Map&, std::unique_ptr<mbgl::style::SymbolLayer>);
+
~SymbolLayer();
// Property getters
diff --git a/platform/android/src/style/layers/unknown_layer.cpp b/platform/android/src/style/layers/unknown_layer.cpp
new file mode 100644
index 0000000000..9ec963a41b
--- /dev/null
+++ b/platform/android/src/style/layers/unknown_layer.cpp
@@ -0,0 +1,49 @@
+#include "unknown_layer.hpp"
+
+#include <string>
+
+namespace {
+
+ // Dummy initializer (We don't support initializing this from the JVM)
+ std::unique_ptr<mbgl::android::UnknownLayer> init(jni::JNIEnv&) {
+ throw new std::runtime_error("UnknownLayer should not be initialized from the JVM");
+ }
+
+} // namespace
+
+namespace mbgl {
+namespace android {
+
+ UnknownLayer::UnknownLayer(mbgl::Map& map, mbgl::style::Layer& coreLayer)
+ : Layer(map, coreLayer) {
+ }
+
+ UnknownLayer::UnknownLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
+ jni::Class<UnknownLayer> UnknownLayer::javaClass;
+
+ jni::jobject* UnknownLayer::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = UnknownLayer::javaClass.template GetConstructor<jni::jlong>(env);
+ return UnknownLayer::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void UnknownLayer::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ UnknownLayer::javaClass = *jni::Class<UnknownLayer>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ std::function<std::unique_ptr<UnknownLayer>(JNIEnv&)> initializer = nullptr;
+
+ // Register the peer
+ jni::RegisterNativePeer<UnknownLayer>(
+ env, UnknownLayer::javaClass, "nativePtr",
+ init,
+ "initialize",
+ "finalize");
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/layers/unknown_layer.hpp b/platform/android/src/style/layers/unknown_layer.hpp
new file mode 100644
index 0000000000..67992ea007
--- /dev/null
+++ b/platform/android/src/style/layers/unknown_layer.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "layer.hpp"
+#include <mbgl/style/layer.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class UnknownLayer : public Layer {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/layers/UnknownLayer"; };
+
+ static jni::Class<UnknownLayer> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ UnknownLayer(mbgl::Map&, mbgl::style::Layer&);
+
+ UnknownLayer(mbgl::Map&, std::unique_ptr<mbgl::style::Layer>);
+
+ ~UnknownLayer() = default;
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class UnknownLayer
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp
index 234dccb315..37ce0644c1 100644
--- a/platform/android/src/style/sources/geojson_source.cpp
+++ b/platform/android/src/style/sources/geojson_source.cpp
@@ -27,19 +27,19 @@ namespace android {
void GeoJSONSource::setGeoJSON(jni::JNIEnv& env, jni::Object<> json) {
using namespace mbgl::style::conversion;
- //Convert the jni object
+ // Convert the jni object
Result<GeoJSON> converted = convert<GeoJSON>(Value(env, json));
if(!converted) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + converted.error().message);
return;
}
- //Update the core source
+ // Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setGeoJSON(*converted);
}
void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) {
- //Update the core source
+ // Update the core source
source.as<mbgl::style::GeoJSONSource>()->GeoJSONSource::setURL(jni::Make<std::string>(env, url));
}
@@ -51,12 +51,12 @@ namespace android {
}
void GeoJSONSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
GeoJSONSource::javaClass = *jni::Class<GeoJSONSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<GeoJSONSource>(
env, GeoJSONSource::javaClass, "nativePtr",
std::make_unique<GeoJSONSource, JNIEnv&, jni::String, jni::Object<>>,
diff --git a/platform/android/src/style/sources/raster_source.cpp b/platform/android/src/style/sources/raster_source.cpp
index b56b56676d..42ac4cda99 100644
--- a/platform/android/src/style/sources/raster_source.cpp
+++ b/platform/android/src/style/sources/raster_source.cpp
@@ -36,12 +36,12 @@ namespace android {
}
void RasterSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
RasterSource::javaClass = *jni::Class<RasterSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<RasterSource>(
env, RasterSource::javaClass, "nativePtr",
std::make_unique<RasterSource, JNIEnv&, jni::String, jni::Object<>, jni::jint>,
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index aca7bd6a84..b780de5627 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -5,11 +5,11 @@
#include <mbgl/util/logging.hpp>
-//Java -> C++ conversion
+// Java -> C++ conversion
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/source.hpp>
-//C++ -> Java conversion
+// C++ -> Java conversion
#include "../conversion/property_value.hpp"
#include <string>
@@ -44,15 +44,15 @@ namespace android {
}
void Source::addToMap(mbgl::Map& _map) {
- //Check to see if we own the source first
+ // Check to see if we own the source first
if (!ownedSource) {
throw std::runtime_error("Cannot add source twice");
}
- //Add source to map
+ // Add source to map
_map.addSource(releaseCoreSource());
- //Save pointer to the map
+ // Save pointer to the map
this->map = &_map;
}
@@ -64,17 +64,17 @@ namespace android {
jni::Class<Source> Source::javaClass;
void Source::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
Source::javaClass = *jni::Class<Source>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<Source>(env, Source::javaClass, "nativePtr",
METHOD(&Source::getId, "nativeGetId")
);
}
-} //android
-} //mbgl \ No newline at end of file
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp
index 0e5d354d93..9a9d504d68 100644
--- a/platform/android/src/style/sources/source.hpp
+++ b/platform/android/src/style/sources/source.hpp
@@ -46,22 +46,18 @@ public:
jni::String getId(jni::JNIEnv&);
protected:
- //Release the owned view and return it
+ // Release the owned view and return it
std::unique_ptr<mbgl::style::Source> releaseCoreSource();
- //Set on newly created sources until added to the map
+ // Set on newly created sources until added to the map
std::unique_ptr<mbgl::style::Source> ownedSource;
- //Raw pointer that is valid until the source is removed from the map
+ // Raw pointer that is valid until the source is removed from the map
mbgl::style::Source& source;
- //Map pointer is valid for newly created sources only after adding to the map
+ // Map pointer is valid for newly created sources only after adding to the map
mbgl::Map* map;
};
-} //android
-} //mbgl
-
-
-
-
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp
index 210acd607f..b4e70202b4 100644
--- a/platform/android/src/style/sources/sources.cpp
+++ b/platform/android/src/style/sources/sources.cpp
@@ -8,6 +8,7 @@
#include "source.hpp"
#include "geojson_source.hpp"
#include "raster_source.hpp"
+#include "unknown_source.hpp"
#include "vector_source.hpp"
namespace mbgl {
@@ -22,7 +23,7 @@ Source* initializeSourcePeer(mbgl::Map& map, mbgl::style::Source& coreSource) {
} else if (coreSource.is<mbgl::style::GeoJSONSource>()) {
source = new GeoJSONSource(map, *coreSource.as<mbgl::style::GeoJSONSource>());
} else {
- throw new std::runtime_error("Source type not implemented");
+ source = new UnknownSource(map, coreSource);
}
return source;
@@ -37,10 +38,11 @@ jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style
void registerNativeSources(jni::JNIEnv& env) {
Source::registerNative(env);
- VectorSource::registerNative(env);
- RasterSource::registerNative(env);
GeoJSONSource::registerNative(env);
+ RasterSource::registerNative(env);
+ UnknownSource::registerNative(env);
+ VectorSource::registerNative(env);
}
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/sources/sources.hpp b/platform/android/src/style/sources/sources.hpp
index 3038873733..09a8b35067 100644
--- a/platform/android/src/style/sources/sources.hpp
+++ b/platform/android/src/style/sources/sources.hpp
@@ -9,12 +9,12 @@
namespace mbgl {
namespace android {
-
+
mbgl::android::Source* initializeSourcePeer(mbgl::Map&, mbgl::style::Source&);
-
+
jni::jobject* createJavaSourcePeer(jni::JNIEnv&, mbgl::Map&, mbgl::style::Source&);
-
+
void registerNativeSources(jni::JNIEnv&);
}
-} \ No newline at end of file
+}
diff --git a/platform/android/src/style/sources/unknown_source.cpp b/platform/android/src/style/sources/unknown_source.cpp
new file mode 100644
index 0000000000..c1b1cc8c02
--- /dev/null
+++ b/platform/android/src/style/sources/unknown_source.cpp
@@ -0,0 +1,42 @@
+#include "unknown_source.hpp"
+
+namespace {
+
+ // Dummy initializer (We don't support initializing this from the JVM)
+ std::unique_ptr<mbgl::android::UnknownSource> init(jni::JNIEnv&) {
+ throw new std::runtime_error("UnknownSource should not be initialized from the JVM");
+ }
+
+} // namespace
+
+namespace mbgl {
+namespace android {
+
+ UnknownSource::UnknownSource(mbgl::Map& map, mbgl::style::Source& coreSource)
+ : Source(map, coreSource) {
+ }
+
+ jni::Class<UnknownSource> UnknownSource::javaClass;
+
+ jni::jobject* UnknownSource::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = UnknownSource::javaClass.template GetConstructor<jni::jlong>(env);
+ return UnknownSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void UnknownSource::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ UnknownSource::javaClass = *jni::Class<UnknownSource>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<UnknownSource>(
+ env, UnknownSource::javaClass, "nativePtr",
+ init,
+ "initialize",
+ "finalize"
+ );
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/unknown_source.hpp b/platform/android/src/style/sources/unknown_source.hpp
new file mode 100644
index 0000000000..3c37239792
--- /dev/null
+++ b/platform/android/src/style/sources/unknown_source.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "source.hpp"
+#include <mbgl/style/source.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class UnknownSource : public Source {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/UnknownSource"; };
+
+ static jni::Class<UnknownSource> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ UnknownSource(mbgl::Map&, mbgl::style::Source&);
+
+ ~UnknownSource() = default;
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class UnknownSource
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/vector_source.cpp b/platform/android/src/style/sources/vector_source.cpp
index 0d065a3348..e60d8d4641 100644
--- a/platform/android/src/style/sources/vector_source.cpp
+++ b/platform/android/src/style/sources/vector_source.cpp
@@ -35,12 +35,12 @@ namespace android {
}
void VectorSource::registerNative(jni::JNIEnv& env) {
- //Lookup the class
+ // Lookup the class
VectorSource::javaClass = *jni::Class<VectorSource>::Find(env).NewGlobalRef(env).release();
#define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
- //Register the peer
+ // Register the peer
jni::RegisterNativePeer<VectorSource>(
env, VectorSource::javaClass, "nativePtr",
std::make_unique<VectorSource, JNIEnv&, jni::String, jni::Object<>>,
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
index c8aad1682b..0b5d81feb1 100644
--- a/platform/android/src/style/value.cpp
+++ b/platform/android/src/style/value.cpp
@@ -20,7 +20,7 @@ namespace android {
JNIEnv& env;
};
- //Instance
+ // Instance
Value::Value(jni::JNIEnv& env, jni::jobject* _value) : jenv(env), value(_value, ObjectDeleter(env)) {}
diff --git a/platform/android/src/test/Main.java b/platform/android/src/test/Main.java
index b6f540f666..b0f3aeb7b9 100644
--- a/platform/android/src/test/Main.java
+++ b/platform/android/src/test/Main.java
@@ -3,13 +3,13 @@ public class Main {
public native void runAllTests(String[] args);
public static void main(String[] args) throws Exception {
- //Load the tests
+ // Load the tests
System.loadLibrary("mbgl-test");
- //Run the tests
+ // Run the tests
new Main().runAllTests(args);
- //Exit explicitly otherwise dalvikvm won't quit
+ // Exit explicitly otherwise dalvikvm won't quit
System.exit(0);
}
}
diff --git a/platform/android/src/test/main.jni.cpp b/platform/android/src/test/main.jni.cpp
index f79d7671cb..f96dd6aa5e 100644
--- a/platform/android/src/test/main.jni.cpp
+++ b/platform/android/src/test/main.jni.cpp
@@ -1,7 +1,5 @@
#include "../jni.hpp"
-#include <android/log.h>
-#include <jni/jni.hpp>
#include <jni/jni.hpp>
#include <mbgl/util/logging.hpp>
@@ -9,10 +7,6 @@
#include <vector>
-#pragma clang diagnostic ignored "-Wunused-parameter"
-
-#define MAKE_NATIVE_METHOD(name, sig) jni::MakeNativeMethod<decltype(name), name>( #name, sig )
-
namespace {
// Main class (entry point for tests from dalvikvm)
@@ -48,31 +42,26 @@ struct Main {
} // namespace
-// JNI Bindings to stub the android.util.Log implementation
-
-static jboolean isLoggable(JNIEnv* env, jni::jobject* clazz, jni::jstring* tag, jint level) {
- return true;
-}
-
-static jint println_native(JNIEnv* env, jni::jobject* clazz, jint bufID, jint priority, jni::jstring* jtag, jni::jstring* jmessage) {
- if (jtag == nullptr || jmessage == nullptr) {
- return false;
- }
-
- std::string tag = jni::Make<std::string>(*env, jni::String(jtag));
- std::string message = jni::Make<std::string>(*env, jni::String(jmessage));
-
- return __android_log_print(priority, tag.c_str(), "%s", message.c_str());
-}
-
-static jint logger_entry_max_payload_native(JNIEnv* env, jni::jobject* clazz) {
- return static_cast<jint>(4068);
-}
-
+// We're declaring the function, which is libandroid_runtime.so.
+// It is defined in AndroidRuntime.cpp:
+// https://github.com/android/platform_frameworks_base/blob/master/core/jni/AndroidRuntime.cpp
+// Once this symbol goes away, we'll have to revisit.
+// This method loads and registers all of the Android-native frameworks so that we can use
+// android.util.Log, android.graphics.Bitmap and so on.
+// Setting the weak attribute tells the linker that this symbol is loaded at runtime and avoids
+// a missing symbol error.
+namespace android {
+struct AndroidRuntime {
+ static int startReg(JNIEnv* env) __attribute__((weak));
+};
+} // namespace android
// Main entry point
+extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
+ // Load Android-native jni bindings
+ jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+ android::AndroidRuntime::startReg(&env);
-extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// Load the main library jni bindings
mbgl::Log::Info(mbgl::Event::JNI, "Registering main JNI Methods");
mbgl::android::registerNatives(vm);
@@ -80,22 +69,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
// Load the test library jni bindings
mbgl::Log::Info(mbgl::Event::JNI, "Registering test JNI Methods");
- jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
-
jni::RegisterNatives(env, jni::Class<Main>::Find(env),
jni::MakeNativeMethod<decltype(Main::runAllTests), &Main::runAllTests>("runAllTests"));
- // Bindings for system classes
- struct Log { static constexpr auto Name() { return "android/util/Log"; } };
- try {
- jni::RegisterNatives(env, jni::Class<Log>::Find(env),
- MAKE_NATIVE_METHOD(isLoggable, "(Ljava/lang/String;I)Z"),
- MAKE_NATIVE_METHOD(logger_entry_max_payload_native, "()I"),
- MAKE_NATIVE_METHOD(println_native, "(IILjava/lang/String;Ljava/lang/String;)I")
- );
- } catch (jni::PendingJavaException ex) {
- env.ThrowNew(jni::JavaErrorClass(env), "Could not register Log mocks");
- }
-
return JNI_VERSION_1_6;
}
diff --git a/platform/android/src/timer.cpp b/platform/android/src/timer.cpp
index 2eb003b2bd..2d9ee49e9b 100644
--- a/platform/android/src/timer.cpp
+++ b/platform/android/src/timer.cpp
@@ -23,7 +23,7 @@ public:
repeat = repeat_;
task = std::move(task_);
- //Prevent overflows when timeout is set to Duration::max()
+ // Prevent overflows when timeout is set to Duration::max()
due = (timeout == Duration::max()) ? std::chrono::time_point<Clock>::max() : Clock::now() + timeout;
loop->addRunnable(this);
}
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index 3d775c8a89..254a7cf219 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -42,9 +42,10 @@ underneath.
The user location annotation view, the attribution button, any buttons in
callout views, and any items in the navigation bar are influenced by your
application’s tint color, so choose a tint color that constrasts well with your
-map style. If you intend your style to be used in the dark, consider the impact
-that Night Shift may have on your style’s colors.
+map style.
<% } -%>
+If you intend your style to be used in the dark, consider the impact that Night
+Shift may have on your style’s colors.
### Typography and graphics
@@ -178,7 +179,7 @@ In style JSON | In the SDK
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
-`image` and `video` sources are not supported.
+`canvas`, `image`, and `video` sources are not supported.
### Tile sources
@@ -282,9 +283,15 @@ Array (`-padding`) | `NSValue.edgeInsetsValue` | `NSValue.edgeInsetsValue`
<% } -%>
For padding attributes, note that the arguments to
-`<%- cocoaPrefix %>EdgeInsetsMake()` in Objective-C and
-`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
-order, in contrast to the clockwise order defined by the style specification.
+<% if (iOS) { -%>
+`UIEdgeInsetsMake()` in Objective-C and `UIEdgeInsets(top:left:bottom:right:)`
+in Swift
+<% } else { -%>
+`NSEdgeInsetsMake()` in Objective-C and `EdgeInsets(top:left:bottom:right:)` in
+Swift
+<% } -%>
+are specified in counterclockwise order, in contrast to the clockwise order
+defined by the style specification.
<% if (macOS) { -%>
Additionally, on macOS, a screen coordinate of (0, 0) is located at the
diff --git a/platform/darwin/docs/theme/assets/css/jazzy.css.scss b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
index f081b7f8b1..103ba601dc 100644
--- a/platform/darwin/docs/theme/assets/css/jazzy.css.scss
+++ b/platform/darwin/docs/theme/assets/css/jazzy.css.scss
@@ -383,6 +383,7 @@ pre code {
.nav-group-task[data-name="MGLMultiPoint"],
.nav-group-task[data-name="MGLShape"],
.nav-group-task[data-name="MGLSource"],
+.nav-group-task[data-name="MGLStyleFunction"],
.nav-group-task[data-name="MGLStyleLayer"],
.nav-group-task[data-name="MGLTileSource"],
.nav-group-task[data-name="MGLAbstractShapeSource"],
diff --git a/platform/darwin/mbgl/storage/reachability.h b/platform/darwin/mbgl/storage/reachability.h
index 78e302eafc..e38c9b1e20 100644
--- a/platform/darwin/mbgl/storage/reachability.h
+++ b/platform/darwin/mbgl/storage/reachability.h
@@ -63,7 +63,7 @@ typedef void (^NetworkUnreachable)(MGLReachability * reachability);
+(instancetype)reachabilityWithHostname:(NSString*)hostname;
// This is identical to the function above, but is here to maintain
-//compatibility with Apples original code. (see .m)
+// compatibility with Apples original code. (see .m)
+(instancetype)reachabilityWithHostName:(NSString*)hostname;
+(instancetype)reachabilityForInternetConnection;
+(instancetype)reachabilityWithAddress:(void *)hostAddress;
diff --git a/platform/darwin/mbgl/storage/reachability.m b/platform/darwin/mbgl/storage/reachability.m
index aa6746a2a9..2030e7ef71 100644
--- a/platform/darwin/mbgl/storage/reachability.m
+++ b/platform/darwin/mbgl/storage/reachability.m
@@ -242,10 +242,10 @@ static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRea
// This is for the case where you flick the airplane mode;
// you end up getting something like this:
-//Reachability: WR ct-----
-//Reachability: -- -------
-//Reachability: WR ct-----
-//Reachability: -- -------
+// Reachability: WR ct-----
+// Reachability: -- -------
+// Reachability: WR ct-----
+// Reachability: -- -------
// We treat this as 4 UNREACHABLE triggers - really apple should do better than this
#define testcase (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection)
diff --git a/platform/darwin/mbgl/util/image+MGLAdditions.hpp b/platform/darwin/mbgl/util/image+MGLAdditions.hpp
new file mode 100644
index 0000000000..c738b4523d
--- /dev/null
+++ b/platform/darwin/mbgl/util/image+MGLAdditions.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <mbgl/util/image.hpp>
+
+#include <CoreGraphics/CGImage.h>
+
+// Creates a CGImage from a PremultipliedImage, taking over the memory ownership.
+CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&&);
+
+// Creates a PremultipliedImage by copying the pixels of the CGImage.
+// Does not alter the retain count of the supplied CGImage.
+mbgl::PremultipliedImage MGLPremultipliedImageFromCGImage(CGImageRef);
diff --git a/platform/darwin/resources/de.lproj/Foundation.strings b/platform/darwin/resources/de.lproj/Foundation.strings
new file mode 100644
index 0000000000..e871efbf2f
--- /dev/null
+++ b/platform/darwin/resources/de.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ Uhr";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ Uhr";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "Osten";
+
+/* East, short */
+"COMPASS_E_SHORT" = "O";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "Ost zu Nord";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "OzN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "Ost zu Süd";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "OzS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "Ostnordost";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ONO";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "Ostsüdost";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "OSO";
+
+/* North, long */
+"COMPASS_N_LONG" = "Nord";
+
+/* North, short */
+"COMPASS_N_SHORT" = "N";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "Nord zu Ost";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NzO";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "Nord zu West";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NzW";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "Nordost";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "NO";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "Nordost zu Ost";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NOzO";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "Nordost zu Nord";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NOzN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "Nordnordost";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "NNO";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "Nordnordwest";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "NNW";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "Nordwest";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "NW";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "Nordwest zu Nord";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NWzN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "Nordwest zu West";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NWzW";
+
+/* South, long */
+"COMPASS_S_LONG" = "Süd";
+
+/* South, short */
+"COMPASS_S_SHORT" = "S";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "Süd zu Ost";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "SzO";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "Süd zu West";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "SzW";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "Südost";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "SO";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "Südost zu Ost";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SOzO";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "Südost zu Süd";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SOzS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "Südsüdost";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "SSO";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "Südsüdwest";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "SSW";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "Südwest";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "SW";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "Südwest zu Süd";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SWzS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "Südwest zu West";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SWzW";
+
+/* West, long */
+"COMPASS_W_LONG" = "West";
+
+/* West, short */
+"COMPASS_W_SHORT" = "W";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "West zu Nord";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "WzN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "West zu Süd";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "WzS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "Westnordwest";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "WNW";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "Westsüdwest";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "WSW";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d Grad";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ und %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@ und %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ Ost";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ Ost";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@O";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ zu %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d Minute(n)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ Nord";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ Nord";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ Süd";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ Süd";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d Sekunde(n)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ West";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ West";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@W";
+
diff --git a/platform/darwin/resources/de.lproj/Foundation.stringsdict b/platform/darwin/resources/de.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..776528a99c
--- /dev/null
+++ b/platform/darwin/resources/de.lproj/Foundation.stringsdict
@@ -0,0 +1,38 @@
+<?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>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d Minute</string>
+ <key>other</key>
+ <string>%d Minuten</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d Sekunde</string>
+ <key>other</key>
+ <string>%d Sekunden</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/es.lproj/Foundation.stringsdict b/platform/darwin/resources/es.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..1c599f8bc1
--- /dev/null
+++ b/platform/darwin/resources/es.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d grado</string>
+ <key>other</key>
+ <string>%d grados</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minuto</string>
+ <key>other</key>
+ <string>%d minutos</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d segundo</string>
+ <key>other</key>
+ <string>%d segundos</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/fr.lproj/Foundation.stringsdict b/platform/darwin/resources/fr.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..82cb954df6
--- /dev/null
+++ b/platform/darwin/resources/fr.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d degré</string>
+ <key>other</key>
+ <string>%d degrés</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minute</string>
+ <key>other</key>
+ <string>%d minutes</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d seconde</string>
+ <key>other</key>
+ <string>%d secondes</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/ja.lproj/Foundation.strings b/platform/darwin/resources/ja.lproj/Foundation.strings
new file mode 100644
index 0000000000..b6dd83dac1
--- /dev/null
+++ b/platform/darwin/resources/ja.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@時方向";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@時方向";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "東";
+
+/* East, short */
+"COMPASS_E_SHORT" = "東";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "東微北";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "東微北";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "東微南";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "東微南";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "東北東";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "東北東";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "東南東";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "東南東";
+
+/* North, long */
+"COMPASS_N_LONG" = "北";
+
+/* North, short */
+"COMPASS_N_SHORT" = "北";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "北微東";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "北微東";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "北微西";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "北微西";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "東北";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "東北";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "東北微東";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "東北微東";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "東北微北";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "東北微北";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "北北東";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "北北東";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "北北西";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "北北西";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "西北";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "西北";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "西北微北";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "西北微北";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "西北微西";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "西北微西";
+
+/* South, long */
+"COMPASS_S_LONG" = "南";
+
+/* South, short */
+"COMPASS_S_SHORT" = "南";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "南微東";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "南微東";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "南微西";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "南微西";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "東南";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "東南";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "東南微東";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "東南微東";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "東南微南";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "東南微南";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "南南東";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "南南東";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "南南西";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "南南西";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "西南";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "西南";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "西南微南";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "西南微南";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "西南微西";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "西南微西";
+
+/* West, long */
+"COMPASS_W_LONG" = "西";
+
+/* West, short */
+"COMPASS_W_SHORT" = "西";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "西微北";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "西微北";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "西微南";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "西微南";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "西北西";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "西北西";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "西南西";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "西南西";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d度";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@度%2$@分";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@度%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%度2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@度%2$@分%3$@秒";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@度%2$@分%3$@秒";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%度2$@分%3$@秒";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "東%@";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "東%@";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@E";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@,%2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@,%2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@,%2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d分";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "北%@";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "北%@";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "南%@";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "南%@";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d秒";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "西%@";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "西%@";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@W";
+
diff --git a/platform/darwin/resources/pl.lproj/Foundation.stringsdict b/platform/darwin/resources/pl.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..016ba06b81
--- /dev/null
+++ b/platform/darwin/resources/pl.lproj/Foundation.stringsdict
@@ -0,0 +1,60 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d stopień</string>
+ <key>few</key>
+ <string>%d stopnie</string>
+ <key>many</key>
+ <string>%d stopni</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minuta</string>
+ <key>few</key>
+ <string>%d minuty</string>
+ <key>many</key>
+ <string>%d minut</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d sekunda</string>
+ <key>few</key>
+ <string>%d sekundy</string>
+ <key>many</key>
+ <string>%d sekund</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/pt-BR.lproj/Foundation.stringsdict b/platform/darwin/resources/pt-BR.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..e99e86d98d
--- /dev/null
+++ b/platform/darwin/resources/pt-BR.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d grau</string>
+ <key>other</key>
+ <string>%d graus</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minuto</string>
+ <key>other</key>
+ <string>%d minutos</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d segundo</string>
+ <key>other</key>
+ <string>%d segundos</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/ru.lproj/Foundation.stringsdict b/platform/darwin/resources/ru.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..b2d7467fd4
--- /dev/null
+++ b/platform/darwin/resources/ru.lproj/Foundation.stringsdict
@@ -0,0 +1,60 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d градус</string>
+ <key>few</key>
+ <string>%d градуса</string>
+ <key>many</key>
+ <string>%d градусов</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d минута</string>
+ <key>few</key>
+ <string>%d минуты</string>
+ <key>many</key>
+ <string>%d минут</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d секунда</string>
+ <key>few</key>
+ <string>%d секунды</string>
+ <key>many</key>
+ <string>%d секунд</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/sv.lproj/Foundation.strings b/platform/darwin/resources/sv.lproj/Foundation.strings
new file mode 100644
index 0000000000..cac46cac1a
--- /dev/null
+++ b/platform/darwin/resources/sv.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "Öst";
+
+/* East, short */
+"COMPASS_E_SHORT" = "O";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "Ost till Nord";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "OtN";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "Ost till Syd";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "OtS";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "Ostnordost";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ONO";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "Ostsydost";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "OSO";
+
+/* North, long */
+"COMPASS_N_LONG" = "Nord";
+
+/* North, short */
+"COMPASS_N_SHORT" = "N";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "Nord till Ost";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "NtO";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "Nord till Väst";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "NtV";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "Nordost";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "NO";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "Nordost till ost";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "NOtO";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "Nordost till nord";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "NOtN";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "Nordnordost";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "NNO";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "Nordnordväst";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "NNV";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "Nordväst";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "NV";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "Nordväst till nord";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "NVtN";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "Nordväst till väst";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "NVtV";
+
+/* South, long */
+"COMPASS_S_LONG" = "Syd";
+
+/* South, short */
+"COMPASS_S_SHORT" = "S";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "Syd till ost";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "StO";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "Syd till väst";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "StV";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "Sydost";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "SO";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "Sydost till ost";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "SOtO";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "Sydost till syd";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "SOtS";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "Sydsydost";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "SSO";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "Sydsydväst";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "SSV";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "Sydväst";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "SV";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "Sydväst till syd";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "SVtS";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "Sydväst till väst";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "SVtV";
+
+/* West, long */
+"COMPASS_W_LONG" = "Väst";
+
+/* West, short */
+"COMPASS_W_SHORT" = "V";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "Väst till nord";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "VtN";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "Väst till syd";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "VtS";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "Västnordväst";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "VNV";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "Västsydväst";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "VSV";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d grad(er)";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ och %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@ och %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ Öst";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ Öst";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@O";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ till %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d minut(er)";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%dm";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%dm";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ Nord";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ Nord";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ Syd";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ Syd";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d sekund(er)";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%ds";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%ds";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ Väst";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ Väst";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@W";
+
diff --git a/platform/darwin/resources/sv.lproj/Foundation.stringsdict b/platform/darwin/resources/sv.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..e438ca02bf
--- /dev/null
+++ b/platform/darwin/resources/sv.lproj/Foundation.stringsdict
@@ -0,0 +1,54 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d grad</string>
+ <key>other</key>
+ <string>%d grader</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d minut</string>
+ <key>other</key>
+ <string>%d minuter</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d sekund</string>
+ <key>other</key>
+ <string>%d sekunder</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/uk.lproj/Foundation.stringsdict b/platform/darwin/resources/uk.lproj/Foundation.stringsdict
new file mode 100644
index 0000000000..76dbbfc5e9
--- /dev/null
+++ b/platform/darwin/resources/uk.lproj/Foundation.stringsdict
@@ -0,0 +1,60 @@
+<?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>COORD_DEG_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@degrees@</string>
+ <key>degrees</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d градус</string>
+ <key>few</key>
+ <string>%d градуси</string>
+ <key>many</key>
+ <string>%d градусів</string>
+ </dict>
+ </dict>
+ <key>COORD_MIN_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@minutes@</string>
+ <key>minutes</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d хвилина</string>
+ <key>few</key>
+ <string>%d хвилини</string>
+ <key>many</key>
+ <string>%d хвилин</string>
+ </dict>
+ </dict>
+ <key>COORD_SEC_LONG</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>%#@seconds@</string>
+ <key>seconds</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>d</string>
+ <key>one</key>
+ <string>%d секунда</string>
+ <key>few</key>
+ <string>%d секунди</string>
+ <key>many</key>
+ <string>%d секунд</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/darwin/resources/vi.lproj/Foundation.strings b/platform/darwin/resources/vi.lproj/Foundation.strings
new file mode 100644
index 0000000000..f29f8e8730
--- /dev/null
+++ b/platform/darwin/resources/vi.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@ giờ";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@ giờ";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "đông";
+
+/* East, short */
+"COMPASS_E_SHORT" = "Đ";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "đông về bắc";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "ĐvB";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "đông về nam";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "ĐvN";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "đông đông bắc";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "ĐĐB";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "đông đông nam";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "ĐĐN";
+
+/* North, long */
+"COMPASS_N_LONG" = "bắc";
+
+/* North, short */
+"COMPASS_N_SHORT" = "B";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "bắc về đông";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "BvĐ";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "bắc về tây";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "BvT";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "đông bắc";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "ĐB";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "đông bắc về đông";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "ĐBvĐ";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "đông bắc về bắc";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "ĐBvB";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "bắc đông bắc";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "BĐB";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "bắc tây bắc";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "BTB";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "tây bắc";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "TB";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "tây bắc về bắc";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "TBvB";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "tây bắc về tây";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "TBvT";
+
+/* South, long */
+"COMPASS_S_LONG" = "nam";
+
+/* South, short */
+"COMPASS_S_SHORT" = "N";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "nam về đông";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "NvĐ";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "nam về tây";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "NvT";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "đông nam";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "ĐN";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "đông nam về đông";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "ĐNvĐ";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "đông nam về nam";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "ĐNvN";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "nam đông nam";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "NĐN";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "nam tây nam";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "NTN";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "tây nam";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "TN";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "tây nam về nam";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "TNvN";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "tây nam về tây";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "TNvT";
+
+/* West, long */
+"COMPASS_W_LONG" = "tây";
+
+/* West, short */
+"COMPASS_W_SHORT" = "T";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "tây về bắc";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "TvB";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "tây về nam";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "TvN";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "tây tây bắc";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "TTB";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "tây tây nam";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "TTN";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d độ";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@ %2$@";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@, %2$@, %3$@";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "%@ kinh độ đông";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "%@ đông";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@Đ";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@ và %2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@, %2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@, %2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d phút";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "%@ vĩ độ bắc";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "%@ bắc";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "%@ vĩ độ nam";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "%@ nam";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@N";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d giây";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "%@ kinh độ tây";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "%@ tây";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@T";
+
diff --git a/platform/darwin/resources/zh-Hant.lproj/Foundation.strings b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
new file mode 100644
index 0000000000..41b1d2baae
--- /dev/null
+++ b/platform/darwin/resources/zh-Hant.lproj/Foundation.strings
@@ -0,0 +1,291 @@
+/* Clock position format, long: {hours} o’clock */
+"CLOCK_FMT_LONG" = "%@點";
+
+/* Clock position format, medium: {hours} o’clock */
+"CLOCK_FMT_MEDIUM" = "%@點";
+
+/* Clock position format, short: {hours}:00 */
+"CLOCK_FMT_SHORT" = "%@:00";
+
+/* East, long */
+"COMPASS_E_LONG" = "東";
+
+/* East, short */
+"COMPASS_E_SHORT" = "東";
+
+/* East by north, long */
+"COMPASS_EbN_LONG" = "東微北";
+
+/* East by north, short */
+"COMPASS_EbN_SHORT" = "東微北";
+
+/* East by south, long */
+"COMPASS_EbS_LONG" = "東微南";
+
+/* East by south, short */
+"COMPASS_EbS_SHORT" = "東微南";
+
+/* East-northeast, long */
+"COMPASS_ENE_LONG" = "東北偏東";
+
+/* East-northeast, short */
+"COMPASS_ENE_SHORT" = "東北偏東";
+
+/* East-southeast, long */
+"COMPASS_ESE_LONG" = "東南偏東";
+
+/* East-southeast, short */
+"COMPASS_ESE_SHORT" = "東南偏東";
+
+/* North, long */
+"COMPASS_N_LONG" = "北";
+
+/* North, short */
+"COMPASS_N_SHORT" = "北";
+
+/* North by east, long */
+"COMPASS_NbE_LONG" = "北微東";
+
+/* North by east, short */
+"COMPASS_NbE_SHORT" = "北微東";
+
+/* North by west, long */
+"COMPASS_NbW_LONG" = "北微西";
+
+/* North by west, short */
+"COMPASS_NbW_SHORT" = "北微西";
+
+/* Northeast, long */
+"COMPASS_NE_LONG" = "東北";
+
+/* Northeast, short */
+"COMPASS_NE_SHORT" = "東北";
+
+/* Northeast by east, long */
+"COMPASS_NEbE_LONG" = "東北微東";
+
+/* Northeast by east, short */
+"COMPASS_NEbE_SHORT" = "東北微東";
+
+/* Northeast by north, long */
+"COMPASS_NEbN_LONG" = "東北微北";
+
+/* Northeast by north, short */
+"COMPASS_NEbN_SHORT" = "東北微北";
+
+/* North-northeast, long */
+"COMPASS_NNE_LONG" = "東北偏北";
+
+/* North-northeast, short */
+"COMPASS_NNE_SHORT" = "東北偏北";
+
+/* North-northwest, long */
+"COMPASS_NNW_LONG" = "西北偏北";
+
+/* North-northwest, short */
+"COMPASS_NNW_SHORT" = "西北偏北";
+
+/* Northwest, long */
+"COMPASS_NW_LONG" = "西北";
+
+/* Northwest, short */
+"COMPASS_NW_SHORT" = "西北";
+
+/* Northwest by north, long */
+"COMPASS_NWbN_LONG" = "西北微北";
+
+/* Northwest by north, short */
+"COMPASS_NWbN_SHORT" = "西北微北";
+
+/* Northwest by west, long */
+"COMPASS_NWbW_LONG" = "西北微西";
+
+/* Northwest by west, short */
+"COMPASS_NWbW_SHORT" = "西北微西";
+
+/* South, long */
+"COMPASS_S_LONG" = "南";
+
+/* South, short */
+"COMPASS_S_SHORT" = "南";
+
+/* South by east, long */
+"COMPASS_SbE_LONG" = "南微東";
+
+/* South by east, short */
+"COMPASS_SbE_SHORT" = "南微東";
+
+/* South by west, long */
+"COMPASS_SbW_LONG" = "南微西";
+
+/* South by west, short */
+"COMPASS_SbW_SHORT" = "南微西";
+
+/* Southeast, long */
+"COMPASS_SE_LONG" = "東南";
+
+/* Southeast, short */
+"COMPASS_SE_SHORT" = "東南";
+
+/* Southeast by east, long */
+"COMPASS_SEbE_LONG" = "東南微東";
+
+/* Southeast by east, short */
+"COMPASS_SEbE_SHORT" = "東南微東";
+
+/* Southeast by south, long */
+"COMPASS_SEbS_LONG" = "東南微南";
+
+/* Southeast by south, short */
+"COMPASS_SEbS_SHORT" = "東南微南";
+
+/* South-southeast, long */
+"COMPASS_SSE_LONG" = "東南偏南";
+
+/* South-southeast, short */
+"COMPASS_SSE_SHORT" = "東南偏南";
+
+/* South-southwest, long */
+"COMPASS_SSW_LONG" = "西南偏南";
+
+/* South-southwest, short */
+"COMPASS_SSW_SHORT" = "西南偏南";
+
+/* Southwest, long */
+"COMPASS_SW_LONG" = "西南";
+
+/* Southwest, short */
+"COMPASS_SW_SHORT" = "西南";
+
+/* Southwest by south, long */
+"COMPASS_SWbS_LONG" = "西南偏南";
+
+/* Southwest by south, short */
+"COMPASS_SWbS_SHORT" = "西南偏南";
+
+/* Southwest by west, long */
+"COMPASS_SWbW_LONG" = "西南偏西";
+
+/* Southwest by west, short */
+"COMPASS_SWbW_SHORT" = "西南偏西";
+
+/* West, long */
+"COMPASS_W_LONG" = "西";
+
+/* West, short */
+"COMPASS_W_SHORT" = "西";
+
+/* West by north, long */
+"COMPASS_WbN_LONG" = "西微北";
+
+/* West by north, short */
+"COMPASS_WbN_SHORT" = "西微北";
+
+/* West by south, long */
+"COMPASS_WbS_LONG" = "西微南";
+
+/* West by south, short */
+"COMPASS_WbS_SHORT" = "西微南";
+
+/* West-northwest, long */
+"COMPASS_WNW_LONG" = "西北偏西";
+
+/* West-northwest, short */
+"COMPASS_WNW_SHORT" = "西北偏西";
+
+/* West-southwest, long */
+"COMPASS_WSW_LONG" = "西南偏西";
+
+/* West-southwest, short */
+"COMPASS_WSW_SHORT" = "西南偏西";
+
+/* Degrees format, long */
+"COORD_DEG_LONG" = "%d度";
+
+/* Degrees format, medium: {degrees} */
+"COORD_DEG_MEDIUM" = "%d°";
+
+/* Degrees format, short: {degrees} */
+"COORD_DEG_SHORT" = "%d°";
+
+/* Coordinate format, long: {degrees}{minutes} */
+"COORD_DM_LONG" = "%1$@度%2$@分";
+
+/* Coordinate format, medium: {degrees}{minutes} */
+"COORD_DM_MEDIUM" = "%1$@度%2$@";
+
+/* Coordinate format, short: {degrees}{minutes} */
+"COORD_DM_SHORT" = "%1$@%度2$@";
+
+/* Coordinate format, long: {degrees}{minutes}{seconds} */
+"COORD_DMS_LONG" = "%1$@度%2$@分%3$@秒";
+
+/* Coordinate format, medium: {degrees}{minutes}{seconds} */
+"COORD_DMS_MEDIUM" = "%1$@度%2$@分%3$@秒";
+
+/* Coordinate format, short: {degrees}{minutes}{seconds} */
+"COORD_DMS_SHORT" = "%1$@%度2$@分%3$@秒";
+
+/* East longitude format, long: {longitude} */
+"COORD_E_LONG" = "東經%@";
+
+/* East longitude format, medium: {longitude} */
+"COORD_E_MEDIUM" = "東經%@";
+
+/* East longitude format, short: {longitude} */
+"COORD_E_SHORT" = "%@E";
+
+/* Coordinate pair format, long: {latitude}, {longitude} */
+"COORD_FMT_LONG" = "%1$@,%2$@";
+
+/* Coordinate pair format, medium: {latitude}, {longitude} */
+"COORD_FMT_MEDIUM" = "%1$@,%2$@";
+
+/* Coordinate pair format, short: {latitude}, {longitude} */
+"COORD_FMT_SHORT" = "%1$@,%2$@";
+
+/* Minutes format, long */
+"COORD_MIN_LONG" = "%d分";
+
+/* Minutes format, medium: {minutes} */
+"COORD_MIN_MEDIUM" = "%d′";
+
+/* Minutes format, short: {minutes} */
+"COORD_MIN_SHORT" = "%d′";
+
+/* North latitude format, long: {latitude} */
+"COORD_N_LONG" = "北緯%@";
+
+/* North latitude format, medium: {latitude} */
+"COORD_N_MEDIUM" = "北緯%@";
+
+/* North latitude format, short: {latitude} */
+"COORD_N_SHORT" = "%@N";
+
+/* South latitude format, long: {latitude} */
+"COORD_S_LONG" = "南緯%@";
+
+/* South latitude format, medium: {latitude} */
+"COORD_S_MEDIUM" = "南緯%@";
+
+/* South latitude format, short: {latitude} */
+"COORD_S_SHORT" = "%@S";
+
+/* Seconds format, long */
+"COORD_SEC_LONG" = "%d秒";
+
+/* Seconds format, medium: {seconds} */
+"COORD_SEC_MEDIUM" = "%d″";
+
+/* Seconds format, short: {seconds} */
+"COORD_SEC_SHORT" = "%d″";
+
+/* West longitude format, long: {longitude} */
+"COORD_W_LONG" = "西經%@";
+
+/* West longitude format, medium: {longitude} */
+"COORD_W_MEDIUM" = "西經%@";
+
+/* West longitude format, short: {longitude} */
+"COORD_W_SHORT" = "%@W";
+
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 3998246580..cacca57700 100644
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -11,7 +11,7 @@ const cocoaConventions = require('./style-spec-cocoa-conventions-v8.json');
const prefix = 'MGL';
const suffix = 'StyleLayer';
-let spec = _.merge(require('mapbox-gl-style-spec').latest, require('./style-spec-overrides-v8.json'));
+let spec = _.merge(require('../../../mapbox-gl-js/src/style-spec/reference/v8'), require('./style-spec-overrides-v8.json'));
///
// Temporarily IGNORE layers that are in the spec yet still not supported in mbgl core
@@ -31,7 +31,7 @@ _.forOwn(cocoaConventions, function (properties, kind) {
}
delete spec[kind][oldName];
spec[kind][newName] = property;
-
+
// Update requirements in other properties.
let updateRequirements = function (property, name) {
let requires = property.requires || [];
@@ -225,7 +225,7 @@ global.testHelperMessage = function (property, layerType, isFunction) {
};
global.propertyDoc = function (propertyName, property, layerType, kind) {
- // Match references to other property names & values.
+ // Match references to other property names & values.
// Requires the format 'When `foo` is set to `bar`,'.
let doc = property.doc.replace(/`([^`]+?)` is set to `([^`]+?)`/g, function (m, peerPropertyName, propertyValue, offset, str) {
let otherProperty = camelizeWithLeadingLowercase(peerPropertyName);
@@ -280,6 +280,30 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
}
doc += `\n\nThis attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#${anchor}"><code>${property.original}</code></a> layout property in the Mapbox Style Specification.`;
}
+ doc += '\n\nYou can set this property to an instance of:\n\n' +
+ '* `MGLStyleConstantValue`\n';
+ if (property["property-function"]) {
+ doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
+ ' * `MGLInterpolationModeExponential`\n' +
+ ' * `MGLInterpolationModeInterval`\n' +
+ '* `MGLSourceStyleFunction` with an interpolation mode of:\n' +
+ ' * `MGLInterpolationModeExponential`\n' +
+ ' * `MGLInterpolationModeInterval`\n' +
+ ' * `MGLInterpolationModeCategorical`\n' +
+ ' * `MGLInterpolationModeIdentity`\n' +
+ '* `MGLCompositeStyleFunction` with an interpolation mode of:\n' +
+ ' * `MGLInterpolationModeExponential`\n' +
+ ' * `MGLInterpolationModeInterval`\n' +
+ ' * `MGLInterpolationModeCategorical`\n';
+ } else {
+ if (property.function === "interpolated") {
+ doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
+ ' * `MGLInterpolationModeExponential`\n' +
+ ' * `MGLInterpolationModeInterval`\n';
+ } else {
+ doc += '* `MGLCameraStyleFunction` with an interpolation mode of `MGLInterpolationModeInterval`\n';
+ }
+ }
}
return doc;
};
@@ -410,6 +434,13 @@ global.propertyType = function (property) {
}
};
+global.isInterpolatable = function (property) {
+ const type = property.type === 'array' ? property.value : property.type;
+ return type !== 'boolean' &&
+ type !== 'enum' &&
+ type !== 'string';
+};
+
global.valueTransformerArguments = function (property) {
let objCType = propertyType(property);
switch (property.type) {
@@ -420,7 +451,7 @@ global.valueTransformerArguments = function (property) {
case 'string':
return ['std::string', objCType];
case 'enum':
- return [`mbgl::style::${mbglType(property)}`, objCType];
+ return [mbglType(property), 'NSValue *', mbglType(property), `MGL${camelize(property.name)}`];
case 'color':
return ['mbgl::Color', objCType];
case 'array':
@@ -561,13 +592,13 @@ for (var layer of layers) {
if (enumProperties.length) {
layer.enumProperties = enumProperties;
}
-
+
let renamedProperties = {};
_.assign(renamedProperties, _.filter(layer.properties, prop => 'original' in prop || 'getter' in prop));
if (!_.isEmpty(renamedProperties)) {
renamedPropertiesByLayerType[layer.type] = renamedProperties;
}
-
+
fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js
index 6291326068..404cda102a 100644
--- a/platform/darwin/scripts/update-examples.js
+++ b/platform/darwin/scripts/update-examples.js
@@ -10,9 +10,9 @@ const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampl
// /** Front matter to describe the example. **/
// func testMGLClass$member() {
// ...
-// //#-example-code
+// // #-example-code
// let sampleCode: String?
-// //#-end-example-code
+// // #-end-example-code
// ...
// }
//
@@ -35,16 +35,16 @@ function completeSymbolInSource(src, line, exampleCode) {
// Split the file contents right before the symbol declaration (but after its documentation comment).
let srcUpToSymbol = src.split('\n', line - 1).join('\n');
let srcFromSymbol = src.substr(srcUpToSymbol.length);
-
+
// Match the documentation comment block that is not followed by the beginning or end of a declaration.
let commentMatch = srcUpToSymbol.match(/\/\*\*\s*(?:[^*]|\*(?!\/))+?\s*\*\/[^;{}]*?$/);
-
+
// Replace the Swift code block with the test method’s contents.
let completedComment = commentMatch[0].replace(/^([ \t]*)```swift\n[^]*?```/m, function (m, indentation) {
// Apply the original indentation to each line.
return ('```swift\n' + exampleCode + '\n```').replace(/^/gm, indentation);
});
-
+
// Splice the modified comment into the overall file contents.
srcUpToSymbol = (srcUpToSymbol.substr(0, commentMatch.index) + completedComment +
srcUpToSymbol.substr(commentMatch.index + commentMatch[0].length));
@@ -60,13 +60,13 @@ while ((match = exampleRegex.exec(examplesSrc)) !== null) {
// Trim leading whitespace from the example code.
exampleCode = exampleCode.replace(new RegExp('^' + indentation, 'gm'), '');
-
+
examples[testMethodName] = exampleCode;
}
function completeExamples(os) {
console.log(`Installing ${os} SDK examples…`);
-
+
let sdk = os === 'iOS' ? 'iphonesimulator' : 'macosx';
let sysroot = execFileSync('xcrun', ['--show-sdk-path', '--sdk', sdk]).toString().trim();
let umbrellaPath = `platform/${os.toLowerCase()}/src/Mapbox.h`;
@@ -88,17 +88,17 @@ function completeExamples(os) {
_.forEachRight(substructure['key.substructure'], function (substructure, idx, substructures) {
completeSubstructure(substructure, idx, substructures, _.concat(symbolPath, substructure['key.name']));
});
-
+
let comment = substructure['key.doc.comment'];
if (!comment || !comment.match(/^(?:\s*)```swift\n/m)) {
return;
}
-
+
// Lazily read in the existing file.
if (!src) {
newSrc = src = fs.readFileSync(path, 'utf8');
}
-
+
// Get the contents of the test method whose name matches the symbol path.
let testMethodName = symbolPath.join('$').replace(/\$[+-]/, '$').replace(/:/g, '_');
let example = examples[testMethodName];
@@ -106,23 +106,23 @@ function completeExamples(os) {
console.error(`MGLDocumentationExampleTests.${testMethodName}() not found.`);
process.exit(1);
}
-
+
// Resolve conditional compilation blocks.
- example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\n/gm,
+ example = example.replace(/^(\s*)#if\s+os\((iOS|macOS)\)\n([^]*?)(?:^\1#else\n([^]*?))?^\1#endif\b\n?/gm,
function (m, indentation, ifOs, ifCase, elseCase) {
return (os === ifOs ? ifCase : elseCase).replace(new RegExp('^ ', 'gm'), '');
- });
-
+ }).replace(/\n$/, '');
+
// Insert the test method contents into the documentation comment just
// above the substructure.
let startLine = substructure['key.parsed_scope.start'];
newSrc = completeSymbolInSource(newSrc, startLine, example);
});
-
+
if (!src) {
return;
}
-
+
// Write out the modified file contents.
if (src === newSrc) {
console.log('Skipping', path);
diff --git a/platform/darwin/src/MGLAccountManager.h b/platform/darwin/src/MGLAccountManager.h
index c1aebd879c..741cc323cb 100644
--- a/platform/darwin/src/MGLAccountManager.h
+++ b/platform/darwin/src/MGLAccountManager.h
@@ -17,17 +17,17 @@ MGL_EXPORT
Set the
<a href="https://www.mapbox.com/help/define-access-token/">Mapbox access token</a>
to be used by all instances of MGLMapView in the current application.
-
+
Mapbox-hosted vector tiles and styles require an API access token, which you
can obtain from the
<a href="https://www.mapbox.com/studio/account/tokens/">Mapbox account page</a>.
Access tokens associate requests to Mapbox’s vector tile and style APIs with
your Mapbox account. They also deter other developers from using your styles
without your permission.
-
+
@param accessToken A Mapbox access token. Calling this method with a value of
`nil` has no effect.
-
+
@note You must set the access token before attempting to load any Mapbox-hosted
style. Therefore, you should generally set it before creating an instance of
MGLMapView. The recommended way to set an access token is to add an entry to
diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m
index 31baf4e249..0f5d033031 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -65,7 +65,7 @@
if (!accessToken.length) {
return;
}
-
+
[MGLAccountManager sharedManager].accessToken = accessToken;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
diff --git a/platform/darwin/src/MGLAnnotation.h b/platform/darwin/src/MGLAnnotation.h
index 4c8f600240..a0a58e83a6 100644
--- a/platform/darwin/src/MGLAnnotation.h
+++ b/platform/darwin/src/MGLAnnotation.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
the visual representation of the annotation but typically coordinate (in
conjunction with the map view’s delegate) the creation of an appropriate
objects to handle the display.
-
+
An object that adopts this protocol must implement the `coordinate` property.
The other methods of this protocol are optional.
*/
@@ -33,7 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
The string containing the annotation’s title.
-
+
Although this property is optional, if you support the selection of annotations
in your map view, you are expected to provide this property. This string is
displayed in the callout for the associated annotation.
@@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
The string containing the annotation’s subtitle.
-
+
This string is displayed in the callout for the associated annotation.
*/
@property (nonatomic, readonly, copy, nullable) NSString *subtitle;
diff --git a/platform/darwin/src/MGLAttributionInfo.h b/platform/darwin/src/MGLAttributionInfo.h
index c4e037059e..031a10060f 100644
--- a/platform/darwin/src/MGLAttributionInfo.h
+++ b/platform/darwin/src/MGLAttributionInfo.h
@@ -16,7 +16,7 @@ MGL_EXPORT
/**
Returns an initialized attribution info object with the given title and URL.
-
+
@param title The attribution statement’s title.
@param URL A URL to more information about the entity named in the attribution.
@return An initialized attribution info object.
@@ -30,7 +30,7 @@ MGL_EXPORT
/**
The URL to more information about the entity named in the attribution.
-
+
If this property is set, the attribution statement should be displayed as a
hyperlink or action button. Otherwise, if it is `nil`, the attribution
statement should be displayed as plain text.
@@ -40,7 +40,7 @@ MGL_EXPORT
/**
A Boolean value indicating whether the attribution statement is a shortcut to a
feedback tool.
-
+
If this property is set, the statement should be treated as a way for the user
to provide feedback rather than an attribution statement.
*/
@@ -49,7 +49,7 @@ MGL_EXPORT
/**
Returns a copy of the `URL` property modified to account for the given center
coordinate and zoom level.
-
+
@param centerCoordinate The map’s center coordinate.
@param zoomLevel The map’s zoom level. See the `MGLMapView.zoomLevel` property
for more information.
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 2546808b34..fa2ae787a5 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -18,7 +18,7 @@
if (!htmlString) {
return @[];
}
-
+
NSDictionary *options = @{
NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding),
@@ -56,7 +56,7 @@
}
NSString *styledHTML = [NSString stringWithFormat:@"<style type='text/css'>%@</style>%@", css, htmlString];
NSData *htmlData = [styledHTML dataUsingEncoding:NSUTF8StringEncoding];
-
+
#if TARGET_OS_IPHONE
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:htmlData
options:options
@@ -67,7 +67,7 @@
options:options
documentAttributes:nil];
#endif
-
+
NSMutableArray *infos = [NSMutableArray array];
[attributedString enumerateAttribute:NSLinkAttributeName
inRange:attributedString.mgl_wholeRange
@@ -75,7 +75,7 @@
usingBlock:
^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
NSCAssert(!value || [value isKindOfClass:[NSURL class]], @"If present, URL attribute must be an NSURL.");
-
+
// Detect feedback links by the bogus style rule applied above.
NSNumber *strokeWidth = [attributedString attribute:NSStrokeWidthAttributeName
atIndex:range.location
@@ -85,14 +85,14 @@
isFeedbackLink = YES;
[attributedString removeAttribute:NSStrokeWidthAttributeName range:range];
}
-
+
// Omit whitespace-only strings.
NSAttributedString *title = [[attributedString attributedSubstringFromRange:range]
mgl_attributedStringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (!title.length) {
return;
}
-
+
MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:value];
info.feedbackLink = isFeedbackLink;
[infos addObject:info];
@@ -124,7 +124,7 @@
if (!self.feedbackLink) {
return nil;
}
-
+
NSURLComponents *components = [NSURLComponents componentsWithURL:self.URL resolvingAgainstBaseURL:NO];
components.fragment = [NSString stringWithFormat:@"/%.5f/%.5f/%i",
centerCoordinate.longitude, centerCoordinate.latitude, (int)round(zoomLevel + 1)];
@@ -142,7 +142,7 @@
/**
Returns whether the given attribution info object overlaps with the receiver by
its plain text title.
-
+
@return `NSOrderedAscending` if the given object is a superset of the receiver,
`NSOrderedDescending` if it is a subset of the receiver, or `NSOrderedSame`
if there is no overlap.
@@ -179,14 +179,14 @@
didInsertInfo = YES;
}
break;
-
+
case NSOrderedAscending:
// The info object we’re adding is a subset of the existing one.
// Don’t add the object and stop looking.
shouldAddInfo = NO;
*stop = YES;
break;
-
+
default:
break;
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index c9a428b571..4b28fa5266 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Parses and returns the attribution infos contained in the given HTML source
code string.
-
+
@param htmlString The HTML source code to parse.
@param fontSize The default text size in points.
@param linkColor The default link color.
@@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
Adds the given attribution info object to the receiver as long as it isn’t
redundant to any object already in the receiver. Any existing object that is
redundant to the given object is replaced by the given object.
-
+
@param info The info object to add to the receiver.
@return True if the given info object was added to the receiver.
*/
@@ -38,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
Adds each of the given attribution info objects to the receiver as long as it
isn’t redundant to any object already in the receiver. Any existing object that
is redundant to the given object is replaced by the given object.
-
+
@param infos An array of info objects to add to the receiver.
*/
- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.h b/platform/darwin/src/MGLBackgroundStyleLayer.h
index 06d7c9ee08..c6fd6113cb 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.h
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -38,6 +38,13 @@ MGL_EXPORT
This property is only applied to the style if `backgroundPattern` is set to
`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *backgroundColor;
#else
@@ -50,6 +57,13 @@ MGL_EXPORT
This property is only applied to the style if `backgroundPattern` is set to
`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *backgroundColor;
#endif
@@ -60,6 +74,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *backgroundOpacity;
@@ -67,6 +88,12 @@ MGL_EXPORT
Name of image in style images to use for drawing an image background. For
seamless patterns, image width and height must be a factor of two (2, 4, 8,
..., 512).
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *backgroundPattern;
diff --git a/platform/darwin/src/MGLBackgroundStyleLayer.mm b/platform/darwin/src/MGLBackgroundStyleLayer.mm
index caf8ca9681..bcad0aa11b 100644
--- a/platform/darwin/src/MGLBackgroundStyleLayer.mm
+++ b/platform/darwin/src/MGLBackgroundStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -62,8 +62,9 @@
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -86,28 +87,34 @@
- (void)setBackgroundColor:(MGLStyleValue<MGLColor *> *)backgroundColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(backgroundColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toInterpolatablePropertyValue(backgroundColor);
self.rawLayer->setBackgroundColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)backgroundColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getBackgroundColor() ?: self.rawLayer->getDefaultBackgroundColor();
+ auto propertyValue = self.rawLayer->getBackgroundColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(self.rawLayer->getDefaultBackgroundColor());
+ }
return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
}
- (void)setBackgroundOpacity:(MGLStyleValue<NSNumber *> *)backgroundOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(backgroundOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(backgroundOpacity);
self.rawLayer->setBackgroundOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)backgroundOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getBackgroundOpacity() ?: self.rawLayer->getDefaultBackgroundOpacity();
+ auto propertyValue = self.rawLayer->getBackgroundOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultBackgroundOpacity());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -121,7 +128,10 @@
- (MGLStyleValue<NSString *> *)backgroundPattern {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getBackgroundPattern() ?: self.rawLayer->getDefaultBackgroundPattern();
+ auto propertyValue = self.rawLayer->getBackgroundPattern();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultBackgroundPattern());
+ }
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 8d8c4588e7..b3e9ee7161 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the scaling behavior of the circle when the map is pitched.
-
+
Values of this type are used in the `MGLCircleStyleLayer.circleScaleAlignment`
property.
*/
@@ -26,7 +26,7 @@ typedef NS_ENUM(NSUInteger, MGLCircleScaleAlignment) {
/**
Controls the translation reference point.
-
+
Values of this type are used in the `MGLCircleStyleLayer.circleTranslationAnchor`
property.
*/
@@ -54,23 +54,23 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
To display circles on the map whose radii correspond to real-world distances,
use many-sided regular polygons and configure their appearance using an
`MGLFillStyleLayer` object.
-
+
You can access an existing circle style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new circle style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
layer.circleColor = MGLStyleValue(rawValue: .green)
- layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
- 12: MGLStyleValue(rawValue: 2),
- 22: MGLStyleValue(rawValue: 180)
- ])
+ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: [12: MGLStyleValue(rawValue: 2),
+ 22: MGLStyleValue(rawValue: 180)],
+ options: [.interpolationBase: 1.75])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
@@ -88,6 +88,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleBlur;
@@ -98,6 +114,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleColor;
#else
@@ -107,6 +139,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleColor;
#endif
@@ -117,6 +165,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleOpacity;
@@ -128,6 +192,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `5`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleRadius;
@@ -141,6 +221,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-pitch-scale"><code>circle-pitch-scale</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleScaleAlignment;
@@ -153,6 +239,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing
`UIColor.blackColor`. Set this property to `nil` to reset it to the default
value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *circleStrokeColor;
#else
@@ -162,6 +264,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing
`NSColor.blackColor`. Set this property to `nil` to reset it to the default
value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *circleStrokeColor;
#endif
@@ -172,18 +290,50 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeOpacity;
/**
The width of the circle's stroke. Strokes are placed outside of the
- "circle-radius".
+ `circleRadius`.
This property is measured in points.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *circleStrokeWidth;
@@ -200,6 +350,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
#else
@@ -215,6 +372,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate"><code>circle-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslation;
#endif
@@ -234,6 +398,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-circle-translate-anchor"><code>circle-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *circleTranslationAnchor;
diff --git a/platform/darwin/src/MGLCircleStyleLayer.mm b/platform/darwin/src/MGLCircleStyleLayer.mm
index adc5ed8dd3..808e00bc38 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.mm
+++ b/platform/darwin/src/MGLCircleStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -59,7 +59,7 @@ namespace mbgl {
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -112,8 +112,9 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -136,57 +137,69 @@ namespace mbgl {
- (void)setCircleBlur:(MGLStyleValue<NSNumber *> *)circleBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleBlur);
self.rawLayer->setCircleBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleBlur {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleBlur() ?: self.rawLayer->getDefaultCircleBlur();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleBlur();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleBlur());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleColor:(MGLStyleValue<MGLColor *> *)circleColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(circleColor);
self.rawLayer->setCircleColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)circleColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleColor() ?: self.rawLayer->getDefaultCircleColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleOpacity:(MGLStyleValue<NSNumber *> *)circleOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleOpacity);
self.rawLayer->setCircleOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleOpacity() ?: self.rawLayer->getDefaultCircleOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleRadius:(MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleRadius);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleRadius);
self.rawLayer->setCircleRadius(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleRadius {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleRadius() ?: self.rawLayer->getDefaultCircleRadius();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleRadius();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleRadius());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleScaleAlignment:(MGLStyleValue<NSValue *> *)circleScaleAlignment {
@@ -199,7 +212,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)circleScaleAlignment {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCirclePitchScale() ?: self.rawLayer->getDefaultCirclePitchScale();
+ auto propertyValue = self.rawLayer->getCirclePitchScale();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(self.rawLayer->getDefaultCirclePitchScale());
+ }
return MGLStyleValueTransformer<mbgl::style::CirclePitchScaleType, NSValue *, mbgl::style::CirclePitchScaleType, MGLCircleScaleAlignment>().toEnumStyleValue(propertyValue);
}
@@ -213,56 +229,68 @@ namespace mbgl {
- (void)setCircleStrokeColor:(MGLStyleValue<MGLColor *> *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(circleStrokeColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(circleStrokeColor);
self.rawLayer->setCircleStrokeColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)circleStrokeColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleStrokeColor() ?: self.rawLayer->getDefaultCircleStrokeColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleStrokeColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleStrokeOpacity:(MGLStyleValue<NSNumber *> *)circleStrokeOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleStrokeOpacity);
self.rawLayer->setCircleStrokeOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleStrokeOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleStrokeOpacity() ?: self.rawLayer->getDefaultCircleStrokeOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleStrokeOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleStrokeWidth:(MGLStyleValue<NSNumber *> *)circleStrokeWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(circleStrokeWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(circleStrokeWidth);
self.rawLayer->setCircleStrokeWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)circleStrokeWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleStrokeWidth() ?: self.rawLayer->getDefaultCircleStrokeWidth();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getCircleStrokeWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultCircleStrokeWidth());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setCircleTranslation:(MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(circleTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(circleTranslation);
self.rawLayer->setCircleTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)circleTranslation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleTranslate() ?: self.rawLayer->getDefaultCircleTranslate();
+ auto propertyValue = self.rawLayer->getCircleTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultCircleTranslate());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -283,7 +311,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)circleTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getCircleTranslateAnchor() ?: self.rawLayer->getDefaultCircleTranslateAnchor();
+ auto propertyValue = self.rawLayer->getCircleTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultCircleTranslateAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLCircleTranslationAnchor>().toEnumStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLClockDirectionFormatter.h b/platform/darwin/src/MGLClockDirectionFormatter.h
index a428f51c63..86a9452846 100644
--- a/platform/darwin/src/MGLClockDirectionFormatter.h
+++ b/platform/darwin/src/MGLClockDirectionFormatter.h
@@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
of headings relative to the user, known as <i>clock positions</i>. For
example, a value of `90` may be formatted as “3 o’clock”, depending on the
locale.
-
+
Use this class to create localized heading strings when displaying directions
relative to the user’s current location and heading. To format a direction
irrespective of the user’s orientation, use `MGLCompassDirectionFormatter`
@@ -21,14 +21,14 @@ MGL_EXPORT
/**
The unit style used by this formatter.
-
+
This property defaults to `NSFormattingUnitStyleMedium`.
*/
@property (nonatomic) NSFormattingUnitStyle unitStyle;
/**
Returns a clock position string for the provided value.
-
+
@param direction The heading, measured in degrees, where 0° means “straight
ahead” and 90° means “directly to your right”.
@return The clock position string appropriately formatted for the receiver’s
diff --git a/platform/darwin/src/MGLClockDirectionFormatter.m b/platform/darwin/src/MGLClockDirectionFormatter.m
index fd67968e65..62a0ea995d 100644
--- a/platform/darwin/src/MGLClockDirectionFormatter.m
+++ b/platform/darwin/src/MGLClockDirectionFormatter.m
@@ -28,16 +28,16 @@
case NSFormattingUnitStyleShort:
format = NSLocalizedStringWithDefaultValue(@"CLOCK_FMT_SHORT", @"Foundation", nil, @"%@:00", @"Clock position format, short: {hours}:00");
break;
-
+
case NSFormattingUnitStyleMedium:
format = NSLocalizedStringWithDefaultValue(@"CLOCK_FMT_MEDIUM", @"Foundation", nil, @"%@ o’clock", @"Clock position format, medium: {hours} o’clock");
-
+
break;
-
+
case NSFormattingUnitStyleLong:
format = NSLocalizedStringWithDefaultValue(@"CLOCK_FMT_LONG", @"Foundation", nil, @"%@ o’clock", @"Clock position format, long: {hours} o’clock");
break;
-
+
default:
break;
}
diff --git a/platform/darwin/src/MGLCompassDirectionFormatter.h b/platform/darwin/src/MGLCompassDirectionFormatter.h
index 714e1cc035..b4a3087509 100644
--- a/platform/darwin/src/MGLCompassDirectionFormatter.h
+++ b/platform/darwin/src/MGLCompassDirectionFormatter.h
@@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
The `MGLCompassDirectionFormatter` class provides properly formatted
descriptions of absolute headings. For example, a value of `90` may be
formatted as “east”, depending on the locale.
-
+
Use this class to create localized heading strings when displaying directions
irrespective of the user’s current location. To format a direction relative to
the user’s current location, use `MGLClockDirectionFormatter` instead.
@@ -19,14 +19,14 @@ MGL_EXPORT
/**
The unit style used by this formatter.
-
+
This property defaults to `NSFormattingUnitStyleMedium`.
*/
@property (nonatomic) NSFormattingUnitStyle unitStyle;
/**
Returns a heading string for the provided value.
-
+
@param direction The heading, measured in degrees, where 0° means “due north”
and 90° means “due east”.
@return The heading string appropriately formatted for the formatter’s locale.
diff --git a/platform/darwin/src/MGLCompassDirectionFormatter.m b/platform/darwin/src/MGLCompassDirectionFormatter.m
index c46fe9e4d5..5f0cfae6f7 100644
--- a/platform/darwin/src/MGLCompassDirectionFormatter.m
+++ b/platform/darwin/src/MGLCompassDirectionFormatter.m
@@ -28,7 +28,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_NEbE_SHORT", @"Foundation", nil, @"NEbE", @"Northeast by east, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_ENE_SHORT", @"Foundation", nil, @"ENE", @"East-northeast, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_EbN_SHORT", @"Foundation", nil, @"EbN", @"East by north, short"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_E_SHORT", @"Foundation", nil, @"E", @"East, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_EbS_SHORT", @"Foundation", nil, @"EbS", @"East by south, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_ESE_SHORT", @"Foundation", nil, @"ESE", @"East-southeast, short"),
@@ -37,7 +37,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_SEbS_SHORT", @"Foundation", nil, @"SEbS", @"Southeast by south, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SSE_SHORT", @"Foundation", nil, @"SSE", @"South-southeast, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SbE_SHORT", @"Foundation", nil, @"SbE", @"South by east, short"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_S_SHORT", @"Foundation", nil, @"S", @"South, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SbW_SHORT", @"Foundation", nil, @"SbW", @"South by west, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SSW_SHORT", @"Foundation", nil, @"SSW", @"South-southwest, short"),
@@ -46,7 +46,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_SWbW_SHORT", @"Foundation", nil, @"SWbW", @"Southwest by west, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WSW_SHORT", @"Foundation", nil, @"WSW", @"West-southwest, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WbS_SHORT", @"Foundation", nil, @"WbS", @"West by south, short"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_W_SHORT", @"Foundation", nil, @"W", @"West, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WbN_SHORT", @"Foundation", nil, @"WbN", @"West by north, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WNW_SHORT", @"Foundation", nil, @"WNW", @"West-northwest, short"),
@@ -56,7 +56,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_NNW_SHORT", @"Foundation", nil, @"NNW", @"North-northwest, short"),
NSLocalizedStringWithDefaultValue(@"COMPASS_NbW_SHORT", @"Foundation", nil, @"NbW", @"North by west, short"),
];
-
+
longStrings = @[
NSLocalizedStringWithDefaultValue(@"COMPASS_N_LONG", @"Foundation", nil, @"north", @"North, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_NbE_LONG", @"Foundation", nil, @"north by east", @"North by east, long"),
@@ -66,7 +66,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_NEbE_LONG", @"Foundation", nil, @"northeast by east", @"Northeast by east, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_ENE_LONG", @"Foundation", nil, @"east-northeast", @"East-northeast, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_EbN_LONG", @"Foundation", nil, @"east by north", @"East by north, long"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_E_LONG", @"Foundation", nil, @"east", @"East, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_EbS_LONG", @"Foundation", nil, @"east by south", @"East by south, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_ESE_LONG", @"Foundation", nil, @"east-southeast", @"East-southeast, long"),
@@ -75,7 +75,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_SEbS_LONG", @"Foundation", nil, @"southeast by south", @"Southeast by south, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SSE_LONG", @"Foundation", nil, @"south-southeast", @"South-southeast, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SbE_LONG", @"Foundation", nil, @"south by east", @"South by east, long"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_S_LONG", @"Foundation", nil, @"south", @"South, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SbW_LONG", @"Foundation", nil, @"south by west", @"South by west, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_SSW_LONG", @"Foundation", nil, @"south-southwest", @"South-southwest, long"),
@@ -84,7 +84,7 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_SWbW_LONG", @"Foundation", nil, @"southwest by west", @"Southwest by west, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WSW_LONG", @"Foundation", nil, @"west-southwest", @"West-southwest, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WbS_LONG", @"Foundation", nil, @"west by south", @"West by south, long"),
-
+
NSLocalizedStringWithDefaultValue(@"COMPASS_W_LONG", @"Foundation", nil, @"west", @"West, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WbN_LONG", @"Foundation", nil, @"west by north", @"West by north, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_WNW_LONG", @"Foundation", nil, @"west-northwest", @"West-northwest, long"),
@@ -94,15 +94,15 @@
NSLocalizedStringWithDefaultValue(@"COMPASS_NNW_LONG", @"Foundation", nil, @"north-northwest", @"North-northwest, long"),
NSLocalizedStringWithDefaultValue(@"COMPASS_NbW_LONG", @"Foundation", nil, @"north by west", @"North by west, long"),
];
-
+
NSAssert(shortStrings.count == longStrings.count, @"Long and short compass direction string arrays must have the same size.");
});
-
+
NSInteger cardinalPoint = wrap(round(wrap(direction, 0, 360) / 360 * shortStrings.count), 0, shortStrings.count);
switch (self.unitStyle) {
case NSFormattingUnitStyleShort:
return shortStrings[cardinalPoint];
-
+
case NSFormattingUnitStyleMedium:
case NSFormattingUnitStyleLong:
return longStrings[cardinalPoint];
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h
new file mode 100644
index 0000000000..d51ebd775c
--- /dev/null
+++ b/platform/darwin/src/MGLConversion.h
@@ -0,0 +1,135 @@
+#import <Foundation/Foundation.h>
+
+#include <mbgl/util/logging.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/feature.hpp>
+#include <mbgl/util/optional.hpp>
+
+NS_ASSUME_NONNULL_BEGIN
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+/**
+ A minimal wrapper class conforming to the requirements for `objectMember(v, name)` (see mbgl/style/conversion.hpp)
+ This is necessary because using `NSObject*` as the value type in `optional<NSObject*>` causes problems for the ARC,
+ due to things like `optional(const value_type& __v)`
+ */
+class OptionalNSObjectValue {
+public:
+ OptionalNSObjectValue(NSObject * _Nullable _value) : value(_value) {}
+
+ explicit operator bool() const {
+ return value;
+ }
+
+ NSObject * _Nullable operator*() {
+ NSCAssert(this, @"Expected non-null value.");
+ return value;
+ }
+private:
+ NSObject * _Nullable value;
+};
+
+inline bool isUndefined(const id value) {
+ return !value || value == [NSNull null];
+}
+
+inline bool isArray(const id value) {
+ return [value isKindOfClass:[NSArray class]];
+}
+
+inline bool isObject(const id value) {
+ return [value isKindOfClass:[NSDictionary class]];
+}
+
+inline std::size_t arrayLength(const id value) {
+ NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for getLength().");
+ NSArray *array = value;
+ auto length = [array count];
+ NSCAssert(length <= std::numeric_limits<size_t>::max(), @"Array length out of bounds.");
+ return length;
+}
+
+inline NSObject *arrayMember(const id value, std::size_t i) {
+ NSCAssert([value isKindOfClass:[NSArray class]], @"Value must be an NSArray for get(int).");
+ NSCAssert(i < NSUIntegerMax, @"Index must be less than NSUIntegerMax");
+ return [value objectAtIndex: i];
+}
+
+inline OptionalNSObjectValue objectMember(const id value, const char *key) {
+ NSCAssert([value isKindOfClass:[NSDictionary class]], @"Value must be an NSDictionary for get(string).");
+ NSObject *member = [value objectForKey: @(key)];
+ if (member && member != [NSNull null]) {
+ return { member };
+ } else {
+ return { nullptr };
+ }
+}
+
+// Not implemented (unneeded for MGLStyleFunction conversion):
+// optional<Error> eachMember(const NSObject*, Fn&&)
+
+inline bool _isBool(const id value) {
+ if (![value isKindOfClass:[NSNumber class]]) return false;
+ // char: 32-bit boolean
+ // BOOL: 64-bit boolean
+ NSNumber *number = value;
+ return ((strcmp([number objCType], @encode(char)) == 0) ||
+ (strcmp([number objCType], @encode(BOOL)) == 0));
+}
+
+inline bool _isNumber(const id value) {
+ return [value isKindOfClass:[NSNumber class]] && !_isBool(value);
+}
+
+inline bool _isString(const id value) {
+ return [value isKindOfClass:[NSString class]];
+}
+
+inline optional<bool> toBool(const id value) {
+ if (_isBool(value)) {
+ return ((NSNumber *)value).boolValue;
+ } else {
+ return {};
+ }
+}
+
+inline optional<float> toNumber(const id value) {
+ if (_isNumber(value)) {
+ return ((NSNumber *)value).floatValue;
+ } else {
+ return {};
+ }
+}
+
+inline optional<std::string> toString(const id value) {
+ if (_isString(value)) {
+ return std::string(static_cast<const char *>([value UTF8String]));
+ } else {
+ return {};
+ }
+}
+
+inline optional<mbgl::Value> toValue(const id value) {
+ if (isUndefined(value)) {
+ return {};
+ } else if (_isBool(value)) {
+ return { *toBool(value) };
+ } else if ( _isString(value)) {
+ return { *toString(value) };
+ } else if (_isNumber(value)) {
+ // Need to cast to a double here as the float is otherwise considered a bool...
+ return { static_cast<double>(*toNumber(value)) };
+ } else {
+ return {};
+ }
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
+
+NS_ASSUME_NONNULL_END
+
diff --git a/platform/darwin/src/MGLCoordinateFormatter.h b/platform/darwin/src/MGLCoordinateFormatter.h
index c42c196d5a..63f0de8f19 100644
--- a/platform/darwin/src/MGLCoordinateFormatter.h
+++ b/platform/darwin/src/MGLCoordinateFormatter.h
@@ -15,7 +15,7 @@ MGL_EXPORT
/**
Determines whether the output may contain minutes of arc when nonzero.
-
+
The default value of this property is `YES`, causing the receiver to include
minutes of arc in its output. If `allowsSeconds` is `YES`, this property is
ignored and the output always includes minutes of arc.
@@ -24,7 +24,7 @@ MGL_EXPORT
/**
Determines whether the output may contain seconds of arc when nonzero.
-
+
The default value of this property is `YES`, causing the receiver to include
seconds of arc in its output.
*/
@@ -32,14 +32,14 @@ MGL_EXPORT
/**
The unit style used by this formatter.
-
+
The default value of this property is `NSFormattingUnitStyleMedium`.
*/
@property (nonatomic) NSFormattingUnitStyle unitStyle;
/**
Returns a coordinate string for the provided value.
-
+
@param coordinate The coordinate’s value.
@return The coordinate string appropriately formatted for the formatter’s
locale.
diff --git a/platform/darwin/src/MGLCoordinateFormatter.m b/platform/darwin/src/MGLCoordinateFormatter.m
index 682f771faa..fb577d3be3 100644
--- a/platform/darwin/src/MGLCoordinateFormatter.m
+++ b/platform/darwin/src/MGLCoordinateFormatter.m
@@ -28,7 +28,7 @@
negativeLongitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_W_SHORT", @"Foundation", nil, @"%@W", @"West longitude format, short: {longitude}");
stringFormat = NSLocalizedStringWithDefaultValue(@"COORD_FMT_SHORT", @"Foundation", nil, @"%@, %@", @"Coordinate pair format, short: {latitude}, {longitude}");
break;
-
+
case NSFormattingUnitStyleMedium:
positiveLatitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_N_MEDIUM", @"Foundation", nil, @"%@ north", @"North latitude format, medium: {latitude}");
negativeLatitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_S_MEDIUM", @"Foundation", nil, @"%@ south", @"South latitude format, medium: {latitude}");
@@ -36,7 +36,7 @@
negativeLongitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_W_MEDIUM", @"Foundation", nil, @"%@ west", @"West longitude format, medium: {longitude}");
stringFormat = NSLocalizedStringWithDefaultValue(@"COORD_FMT_MEDIUM", @"Foundation", nil, @"%@, %@", @"Coordinate pair format, medium: {latitude}, {longitude}");
break;
-
+
case NSFormattingUnitStyleLong:
positiveLatitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_N_LONG", @"Foundation", nil, @"%@ north", @"North latitude format, long: {latitude}");
negativeLatitudeFormat = NSLocalizedStringWithDefaultValue(@"COORD_S_LONG", @"Foundation", nil, @"%@ south", @"South latitude format, long: {latitude}");
@@ -57,7 +57,7 @@
- (NSString *)stringFromLocationDegrees:(CLLocationDegrees)degrees positiveFormat:(NSString *)positiveFormat negativeFormat:(NSString *)negativeFormat {
CLLocationDegrees minutes = (fabs(degrees) - floor(fabs(degrees))) * 60;
CLLocationDegrees seconds = (minutes - floor(minutes)) * 60;
-
+
NSString *degreesFormat;
NSString *minutesFormat;
NSString *secondsFormat;
@@ -71,7 +71,7 @@
degreesMinutesFormat = NSLocalizedStringWithDefaultValue(@"COORD_DM_SHORT", @"Foundation", nil, @"%@%@", @"Coordinate format, short: {degrees}{minutes}");
degreesMinutesSecondsFormat = NSLocalizedStringWithDefaultValue(@"COORD_DMS_SHORT", @"Foundation", nil, @"%@%@%@", @"Coordinate format, short: {degrees}{minutes}{seconds}");
break;
-
+
case NSFormattingUnitStyleMedium:
degreesFormat = NSLocalizedStringWithDefaultValue(@"COORD_DEG_MEDIUM", @"Foundation", nil, @"%d°", @"Degrees format, medium: {degrees}");
minutesFormat = NSLocalizedStringWithDefaultValue(@"COORD_MIN_MEDIUM", @"Foundation", nil, @"%d′", @"Minutes format, medium: {minutes}");
@@ -79,7 +79,7 @@
degreesMinutesFormat = NSLocalizedStringWithDefaultValue(@"COORD_DM_MEDIUM", @"Foundation", nil, @"%@%@", @"Coordinate format, medium: {degrees}{minutes}");
degreesMinutesSecondsFormat = NSLocalizedStringWithDefaultValue(@"COORD_DMS_MEDIUM", @"Foundation", nil, @"%@%@%@", @"Coordinate format, medium: {degrees}{minutes}{seconds}");
break;
-
+
case NSFormattingUnitStyleLong:
degreesFormat = NSLocalizedStringWithDefaultValue(@"COORD_DEG_LONG", @"Foundation", nil, @"%d degree(s)", @"Degrees format, long");
minutesFormat = NSLocalizedStringWithDefaultValue(@"COORD_MIN_LONG", @"Foundation", nil, @"%d minute(s)", @"Minutes format, long");
@@ -88,9 +88,9 @@
degreesMinutesSecondsFormat = NSLocalizedStringWithDefaultValue(@"COORD_DMS_LONG", @"Foundation", nil, @"%@, %@, and %@", @"Coordinate format, long: {degrees}{minutes}{seconds}");
break;
}
-
+
NSString *degreesString = [NSString stringWithFormat:degreesFormat, (int)floor(fabs(degrees))];
-
+
NSString *string;
if (trunc(seconds) > 0 && self.allowsSeconds) {
NSString *minutesString = [NSString stringWithFormat:minutesFormat, (int)floor(minutes)];
@@ -104,7 +104,7 @@
} else {
string = [NSString stringWithFormat:degreesFormat, (int)round(fabs(degrees))];
}
-
+
if (degrees == 0) {
return string;
}
diff --git a/platform/darwin/src/MGLDistanceFormatter.h b/platform/darwin/src/MGLDistanceFormatter.h
new file mode 100644
index 0000000000..46aad9a940
--- /dev/null
+++ b/platform/darwin/src/MGLDistanceFormatter.h
@@ -0,0 +1,26 @@
+#import <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+
+#import "MGLFoundation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ `MGLDistanceFormatter` implements a formatter object meant to be used for
+ geographic distances. The user’s current locale will be used by default
+ but it can be overriden by changing the locale property of the numberFormatter.
+ */
+MGL_EXPORT
+@interface MGLDistanceFormatter : NSLengthFormatter
+
+/**
+ Returns a localized formatted string for the provided distance.
+
+ @param distance The distance, measured in meters.
+ @return A localized formatted distance string including units.
+ */
+- (NSString *)stringFromDistance:(CLLocationDistance)distance;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLDistanceFormatter.m b/platform/darwin/src/MGLDistanceFormatter.m
new file mode 100644
index 0000000000..e77e48b512
--- /dev/null
+++ b/platform/darwin/src/MGLDistanceFormatter.m
@@ -0,0 +1,35 @@
+#import "MGLDistanceFormatter.h"
+
+@interface MGLDistanceFormatter()
+@end
+
+@implementation MGLDistanceFormatter
+
+static const CLLocationDistance METERS_PER_MILE = 1609.344;
+static const double YARDS_PER_MILE = 1760.0;
+static const double FEET_PER_MILE = YARDS_PER_MILE * 3.0;
+
+- (NSString *)stringFromDistance:(CLLocationDistance)distance {
+ double miles = distance / METERS_PER_MILE;
+ double feet = miles * FEET_PER_MILE;
+
+ NSLengthFormatterUnit unit = NSLengthFormatterUnitMillimeter;
+ [self unitStringFromMeters:distance usedUnit:&unit];
+
+ self.numberFormatter.roundingIncrement = @0.25;
+
+ if (unit == NSLengthFormatterUnitYard) {
+ if (miles > 0.2) {
+ unit = NSLengthFormatterUnitMile;
+ return [self stringFromValue:miles unit:unit];
+ } else {
+ unit = NSLengthFormatterUnitFoot;
+ self.numberFormatter.roundingIncrement = @50;
+ return [self stringFromValue:feet unit:unit];
+ }
+ } else {
+ return [self stringFromMeters:distance];
+ }
+}
+
+@end
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index 82dbb450cf..2380a817e3 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -14,14 +14,14 @@ NS_ASSUME_NONNULL_BEGIN
contained in an `MGLShapeSource` or `MGLVectorSource` object. Each concrete
subclass of `MGLShape` in turn has a subclass that conforms to this protocol. A
feature object associates a shape with an optional identifier and attributes.
-
+
You can add custom data to display on the map by creating feature objects and
adding them to an `MGLShapeSource` using the
`-[MGLShapeSource initWithIdentifier:shape:options:]` method or
`MGLShapeSource.shape` property. Similarly, you can add `MGLPointFeature`,
`MGLPolylineFeature`, and `MGLPolygonFeature` objects to the map as annotations
using `-[MGLMapView addAnnotations:]` and related methods.
-
+
In addition to adding data to the map, you can also extract data from the map:
`-[MGLMapView visibleFeaturesAtPoint:]` and related methods return feature
objects that correspond to features in the source. This enables you to inspect
@@ -33,12 +33,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
An object that uniquely identifies the feature in its containing content
source.
-
+
You can configure an `MGLVectorStyleLayer` object to include or exclude a
specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
`MGLVectorStyleLayer.predicate` property, compare the special `$id` attribute
to the feature’s identifier.
-
+
In vector tiles loaded by `MGLVectorSource` objects, the identifier corresponds
to the
<a href="https://github.com/mapbox/vector-tile-spec/tree/master/2.1#42-features">feature identifier</a>
@@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
this property is `nil`. If specified, the identifier may be an integer,
floating-point number, or string. These data types are mapped to instances of
the following Foundation classes:
-
+
<table>
<thead>
<tr><th>In the tile source</th><th>This property</th></tr>
@@ -57,12 +57,12 @@ NS_ASSUME_NONNULL_BEGIN
<tr><td>String</td> <td><code>NSString</code></td></tr>
</tbody>
</table>
-
+
For details about the identifiers used in most Mapbox-provided styles, consult
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
layer reference.
-
+
The identifier should be set before adding the feature to an `MGLShapeSource`
object; setting it afterwards has no effect on the map’s contents. While it is
possible to change this value on feature instances obtained from
@@ -73,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
A dictionary of attributes for this feature.
-
+
You can configure an `MGLVectorStyleLayer` object to include or exclude a
specific feature in an `MGLShapeSource` or `MGLVectorSource`. In the
`MGLVectorStyleLayer.predicate` property, compare a key of the attribute
@@ -82,20 +82,29 @@ NS_ASSUME_NONNULL_BEGIN
a value above 50 to the important features’ `importance` attribute, then set
`MGLVectorStyleLayer.predicate` to an `NSPredicate` with the format
`importance > 50`.
-
- You can also configure some attributes of an `MGLSymbolStyleLayer` object to
- include the value of an attribute in this dictionary whenever it renders this
- feature. For example, to label features in an `MGLShapeSource` object by their
- names, you can assign a `name` attribute to each of the source’s features, then
- set `MGLSymbolStyleLayer.textField` to an `MGLStyleValue` object containing the
- string `{name}`.
-
+
+ You can also configure many layout and paint attributes of an `MGLStyleLayer`
+ object to match the value of an attribute in this dictionary whenever it
+ renders this feature. For example, if you display features in an
+ `MGLShapeSource` using an `MGLCircleStyleLayer`, you can assign a `halfway`
+ attribute to each of the source’s features, then set
+ `MGLCircleStyleLayer.circleRadius` to an `MGLStyleValue` object with an
+ interpolation mode of `MGLInterpolationModeIdentity` and an attribute name of
+ `halfway`.
+
+ The `MGLSymbolStyleLayer.textField` and `MGLSymbolStyleLayer.iconImageName`
+ properties allow you to use attributes yet another way. For example, to label
+ features in an `MGLShapeSource` object by their names, you can assign a `name`
+ attribute to each of the source’s features, then set
+ `MGLSymbolStyleLayer.textField` to an `MGLStyleValue` object containing the
+ raw string value `{name}`.
+
In vector tiles loaded by `MGLVectorSource` objects, the keys and values of
each feature’s attribute dictionary are determined by the source. Each
attribute name is a string, while each attribute value may be a null value,
Boolean value, integer, floating-point number, or string. These data types are
mapped to instances of the following Foundation classes:
-
+
<table>
<thead>
<tr><th>In the tile source</th><th>In this dictionary</th></tr>
@@ -108,7 +117,7 @@ NS_ASSUME_NONNULL_BEGIN
<tr><td>String</td> <td><code>NSString</code></td></tr>
</tbody>
</table>
-
+
For details about the attribute names and values found in Mapbox-provided
vector tile sources, consult the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets</a>
@@ -116,6 +125,15 @@ NS_ASSUME_NONNULL_BEGIN
<a href="https://www.mapbox.com/vector-tiles/mapbox-terrain/">Mapbox Terrain</a>
layer references.
+ When adding a feature to an `MGLShapeSource`, use the same Foundation types
+ listed above for each attribute value. In addition to the Foundation types, you
+ may also set an attribute to an `NSColor` (macOS) or `UIColor` (iOS), which
+ will be converted into its
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#types-color">CSS string representation</a>
+ when the feature is added to an `MGLShapeSource`. This can be convenient when
+ using the attribute to supply a value for a color-typed layout or paint
+ attribute via the `MGLInterpolationModeIdentity` interpolation mode.
+
Note that while it is possible to change this value on feature
instances obtained from `-[MGLMapView visibleFeaturesAtPoint:]` and related
methods, there will be no effect on the map. Setting this value can be useful
@@ -126,7 +144,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the feature attribute for the given attribute name.
-
+
See the `attributes` property’s documentation for details on keys and values
associated with this method.
*/
@@ -135,10 +153,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a dictionary that can be serialized as a GeoJSON Feature representation
of an instance of an `MGLFeature` subclass.
-
- The dictionary includes a `geometry` key corresponding to the receiver’s
- underlying geometry data, a `properties` key corresponding to the receiver’s
- `attributes` property, and an `id` key corresponding to the receiver’s
+
+ The dictionary includes a `geometry` key corresponding to the receiver’s
+ underlying geometry data, a `properties` key corresponding to the receiver’s
+ `attributes` property, and an `id` key corresponding to the receiver’s
`identifier` property.
*/
- (NS_DICTIONARY_OF(NSString *, id) *)geoJSONDictionary;
@@ -156,7 +174,7 @@ MGL_EXPORT
/**
An `MGLPolylineFeature` object associates a polyline shape with an optional
identifier and attributes.
-
+
A polyline feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
feature in GeoJSON.
@@ -176,7 +194,7 @@ MGL_EXPORT
/**
An `MGLPointCollectionFeature` object associates a point collection with an
optional identifier and attributes.
-
+
A point collection feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
feature in GeoJSON.
@@ -191,7 +209,7 @@ MGL_EXPORT
/**
An `MGLMultiPolylineFeature` object associates a multipolyline shape with an
optional identifier and attributes.
-
+
A multipolyline feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
feature in GeoJSON.
@@ -211,7 +229,7 @@ MGL_EXPORT
/**
An `MGLShapeCollectionFeature` object associates a shape collection with an
optional identifier and attributes.
-
+
A shape collection feature is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.3">feature collection</a>
in GeoJSON.
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index 3bd7eae535..e169ee19bb 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -225,21 +225,21 @@ public:
feature.coordinate = toLocationCoordinate2D(geometry);
return feature;
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::LineString<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
return [MGLPolylineFeature polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::Polygon<T> &geometry) const {
return toShape<MGLPolygonFeature>(geometry);
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::MultiPoint<T> &geometry) const {
std::vector<CLLocationCoordinate2D> coordinates = toLocationCoordinates2D(geometry);
return [[MGLPointCollectionFeature alloc] initWithCoordinates:&coordinates[0] count:coordinates.size()];
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::MultiLineString<T> &geometry) const {
NSMutableArray *polylines = [NSMutableArray arrayWithCapacity:geometry.size()];
for (auto &lineString : geometry) {
@@ -247,19 +247,19 @@ public:
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:&coordinates[0] count:coordinates.size()];
[polylines addObject:polyline];
}
-
+
return [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::MultiPolygon<T> &geometry) const {
NSMutableArray *polygons = [NSMutableArray arrayWithCapacity:geometry.size()];
for (auto &polygon : geometry) {
[polygons addObject:toShape(polygon)];
}
-
+
return [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
}
-
+
MGLShape <MGLFeature> * operator()(const mapbox::geometry::geometry_collection<T> &collection) const {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
for (auto &geometry : collection) {
@@ -269,19 +269,19 @@ public:
}
return [MGLShapeCollectionFeature shapeCollectionWithShapes:shapes];
}
-
+
private:
static CLLocationCoordinate2D toLocationCoordinate2D(const mbgl::Point<T> &point) {
return CLLocationCoordinate2DMake(point.y, point.x);
}
-
+
static std::vector<CLLocationCoordinate2D> toLocationCoordinates2D(const std::vector<mbgl::Point<T>> &points) {
std::vector<CLLocationCoordinate2D> coordinates;
coordinates.reserve(points.size());
std::transform(points.begin(), points.end(), std::back_inserter(coordinates), toLocationCoordinate2D);
return coordinates;
}
-
+
template<typename U = MGLPolygon>
static U *toShape(const mbgl::Polygon<T> &geometry) {
auto &linearRing = geometry.front();
@@ -296,7 +296,7 @@ private:
[innerPolygons addObject:innerPolygon];
}
}
-
+
return [U polygonWithCoordinates:&coordinates[0] count:coordinates.size() interiorPolygons:innerPolygons];
}
};
@@ -309,12 +309,12 @@ public:
MGLShape <MGLFeature> *shape = mapbox::geometry::geometry<T>::visit(geometry, evaluator);
return shape;
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::Feature &feature) const {
MGLShape <MGLFeature> *shape = (MGLShape <MGLFeature> *)MGLFeatureFromMBGLFeature(feature);
return shape;
}
-
+
MGLShape <MGLFeature> * operator()(const mbgl::FeatureCollection &collection) const {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:collection.size()];
for (const auto &feature : collection) {
@@ -345,7 +345,7 @@ id <MGLFeature> MGLFeatureFromMBGLFeature(const mbgl::Feature &feature) {
shape.identifier = mbgl::FeatureIdentifier::visit(*feature.id, ValueEvaluator());
}
shape.attributes = attributes;
-
+
return shape;
}
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
index 6751b3196a..4137200b98 100644
--- a/platform/darwin/src/MGLFeature_Private.h
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -28,7 +28,7 @@ MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson);
/**
Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and
- returns the feature object with converted `mbgl::FeatureIdentifier` and
+ returns the feature object with converted `mbgl::FeatureIdentifier` and
`mbgl::PropertyMap` properties.
*/
mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes);
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index 2ab02acf5a..a5baf2308c 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Controls the translation reference point.
-
+
Values of this type are used in the `MGLFillStyleLayer.fillTranslationAnchor`
property.
*/
@@ -32,15 +32,15 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
multipolygon features in vector tiles loaded by an `MGLVectorSource` object or
`MGLPolygon`, `MGLPolygonFeature`, `MGLMultiPolygon`, or
`MGLMultiPolygonFeature` instances in an `MGLShapeSource` object.
-
+
You can access an existing fill style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new fill style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
layer.sourceLayerIdentifier = "parks"
@@ -64,6 +64,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-antialias"><code>fill-antialias</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable, getter=isFillAntialiased) MGLStyleValue<NSNumber *> *fillAntialiased;
@@ -79,6 +85,22 @@ MGL_EXPORT
This property is only applied to the style if `fillPattern` is set to `nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillColor;
#else
@@ -91,6 +113,22 @@ MGL_EXPORT
This property is only applied to the style if `fillPattern` is set to `nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillColor;
#endif
@@ -102,6 +140,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *fillOpacity;
@@ -112,6 +166,22 @@ MGL_EXPORT
This property is only applied to the style if `fillPattern` is set to `nil`,
and `fillAntialiased` is set to an `MGLStyleValue` object containing an
`NSNumber` object containing `YES`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *fillOutlineColor;
#else
@@ -121,6 +191,22 @@ MGL_EXPORT
This property is only applied to the style if `fillPattern` is set to `nil`,
and `fillAntialiased` is set to an `MGLStyleValue` object containing an
`NSNumber` object containing `YES`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *fillOutlineColor;
#endif
@@ -128,6 +214,12 @@ 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).
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *fillPattern;
@@ -144,6 +236,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
#else
@@ -159,6 +258,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate"><code>fill-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslation;
#endif
@@ -178,6 +284,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-fill-translate-anchor"><code>fill-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *fillTranslationAnchor;
diff --git a/platform/darwin/src/MGLFillStyleLayer.mm b/platform/darwin/src/MGLFillStyleLayer.mm
index 63a482ac2e..6716e0efb1 100644
--- a/platform/darwin/src/MGLFillStyleLayer.mm
+++ b/platform/darwin/src/MGLFillStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -54,7 +54,7 @@ namespace mbgl {
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -107,8 +107,9 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -138,7 +139,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)isFillAntialiased {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillAntialias() ?: self.rawLayer->getDefaultFillAntialias();
+ auto propertyValue = self.rawLayer->getFillAntialias();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultFillAntialias());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -152,43 +156,52 @@ namespace mbgl {
- (void)setFillColor:(MGLStyleValue<MGLColor *> *)fillColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillColor);
self.rawLayer->setFillColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)fillColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillColor() ?: self.rawLayer->getDefaultFillColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getFillColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setFillOpacity:(MGLStyleValue<NSNumber *> *)fillOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(fillOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(fillOpacity);
self.rawLayer->setFillOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)fillOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillOpacity() ?: self.rawLayer->getDefaultFillOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getFillOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setFillOutlineColor:(MGLStyleValue<MGLColor *> *)fillOutlineColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(fillOutlineColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(fillOutlineColor);
self.rawLayer->setFillOutlineColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)fillOutlineColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillOutlineColor() ?: self.rawLayer->getDefaultFillOutlineColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getFillOutlineColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultFillOutlineColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setFillPattern:(MGLStyleValue<NSString *> *)fillPattern {
@@ -201,21 +214,27 @@ namespace mbgl {
- (MGLStyleValue<NSString *> *)fillPattern {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillPattern() ?: self.rawLayer->getDefaultFillPattern();
+ auto propertyValue = self.rawLayer->getFillPattern();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultFillPattern());
+ }
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setFillTranslation:(MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(fillTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(fillTranslation);
self.rawLayer->setFillTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)fillTranslation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillTranslate() ?: self.rawLayer->getDefaultFillTranslate();
+ auto propertyValue = self.rawLayer->getFillTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultFillTranslate());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -236,7 +255,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)fillTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getFillTranslateAnchor() ?: self.rawLayer->getDefaultFillTranslateAnchor();
+ auto propertyValue = self.rawLayer->getFillTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultFillTranslateAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLFillTranslationAnchor>().toEnumStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLForegroundStyleLayer.h b/platform/darwin/src/MGLForegroundStyleLayer.h
index 474e1f6307..87763f4634 100644
--- a/platform/darwin/src/MGLForegroundStyleLayer.h
+++ b/platform/darwin/src/MGLForegroundStyleLayer.h
@@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
`MGLForegroundStyleLayer` is an abstract superclass for style layers whose
content is defined by an `MGLSource` object.
-
+
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLRasterStyleLayer`
and the concrete subclasses of `MGLVectorStyleLayer`.
@@ -25,11 +25,11 @@ MGL_EXPORT
/**
Returns a foreground style layer initialized with an identifier and source.
-
+
After initializing and configuring the style layer, add it to a map view’s
style using the `-[MGLStyle addLayer:]` or
`-[MGLStyle insertLayer:belowLayer:]` method.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param source The source from which to obtain the data to style. If the source
diff --git a/platform/darwin/src/MGLFoundation.mm b/platform/darwin/src/MGLFoundation.mm
new file mode 100644
index 0000000000..1cc56de298
--- /dev/null
+++ b/platform/darwin/src/MGLFoundation.mm
@@ -0,0 +1,4 @@
+#import "MGLFoundation_Private.h"
+
+/// Initializes the run loop shim that lives on the main thread.
+mbgl::util::RunLoop mgl_runLoop;
diff --git a/platform/darwin/src/MGLFoundation_Private.h b/platform/darwin/src/MGLFoundation_Private.h
new file mode 100644
index 0000000000..940bb1df69
--- /dev/null
+++ b/platform/darwin/src/MGLFoundation_Private.h
@@ -0,0 +1,5 @@
+#import "MGLFoundation.h"
+
+#include <mbgl/util/run_loop.hpp>
+
+extern mbgl::util::RunLoop mgl_runLoop;
diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h
index 408bdb2632..9fcb9dd37c 100644
--- a/platform/darwin/src/MGLGeometry.h
+++ b/platform/darwin/src/MGLGeometry.h
@@ -101,7 +101,7 @@ NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsOffset(MGLCoordinateBounds boun
/**
Returns `YES` if the coordinate bounds covers no area.
-
+
@note A bounds may be empty but have a non-zero coordinate span (e.g., when its
northeast point lies due north of its southwest point).
*/
diff --git a/platform/darwin/src/MGLGeometry.mm b/platform/darwin/src/MGLGeometry.mm
index 36e096dd03..8c0c5f9cb7 100644
--- a/platform/darwin/src/MGLGeometry.mm
+++ b/platform/darwin/src/MGLGeometry.mm
@@ -6,7 +6,7 @@
/** Vertical field of view, measured in degrees, for determining the altitude
of the viewpoint.
-
+
TransformState::getProjMatrix() has a variable vertical field of view that
defaults to 2 arctan ⅓ rad ≈ 36.9° but MapKit uses a vertical field of view of 30°.
flyTo() assumes a field of view of 2 arctan ½ rad. */
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index fc57460128..e6b37b3530 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -45,7 +45,7 @@ NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(NSEdgeInsets insets) {
#endif
/** Converts a map zoom level to a camera altitude.
-
+
@param zoomLevel The zoom level to convert.
@param pitch The camera pitch, measured in degrees.
@param latitude The latitude of the point at the center of the viewport.
@@ -54,7 +54,7 @@ NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(NSEdgeInsets insets) {
CLLocationDistance MGLAltitudeForZoomLevel(double zoomLevel, CGFloat pitch, CLLocationDegrees latitude, CGSize size);
/** Converts a camera altitude to a map zoom level.
-
+
@param altitude The altitude to convert, measured in meters.
@param pitch The camera pitch, measured in degrees.
@param latitude The latitude of the point at the center of the viewport.
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 98f2778291..23a1f8f131 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
The display of line endings.
-
+
Values of this type are used in the `MGLLineStyleLayer.lineCap`
property.
*/
@@ -34,7 +34,7 @@ typedef NS_ENUM(NSUInteger, MGLLineCap) {
/**
The display of lines when joining.
-
+
Values of this type are used in the `MGLLineStyleLayer.lineJoin`
property.
*/
@@ -59,7 +59,7 @@ typedef NS_ENUM(NSUInteger, MGLLineJoin) {
/**
Controls the translation reference point.
-
+
Values of this type are used in the `MGLLineStyleLayer.lineTranslationAnchor`
property.
*/
@@ -82,22 +82,22 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
multipolyline features in vector tiles loaded by an `MGLVectorSource` object or
`MGLPolyline`, `MGLPolylineFeature`, `MGLMultiPolyline`, or
`MGLMultiPolylineFeature` instances in an `MGLShapeSource` object.
-
+
You can access an existing line style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new line style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 20),
- ])
+ layer.lineWidth = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: [14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 20)],
+ options: [.interpolationBase: 1.5])
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
@@ -115,6 +115,12 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLLineCapButt`. Set this property to `nil` to
reset it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineCap;
@@ -124,6 +130,12 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLLineJoinMiter`. Set this property to `nil` to
reset it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineJoin;
@@ -137,6 +149,13 @@ MGL_EXPORT
This property is only applied to the style if `lineJoin` is set to an
`MGLStyleValue` object containing an `NSValue` object containing
`MGLLineJoinMiter`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineMiterLimit;
@@ -150,6 +169,13 @@ MGL_EXPORT
This property is only applied to the style if `lineJoin` is set to an
`MGLStyleValue` object containing an `NSValue` object containing
`MGLLineJoinRound`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineRoundLimit;
@@ -163,6 +189,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineBlur;
@@ -176,6 +218,22 @@ MGL_EXPORT
This property is only applied to the style if `linePattern` is set to `nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *lineColor;
#else
@@ -188,6 +246,22 @@ MGL_EXPORT
This property is only applied to the style if `linePattern` is set to `nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *lineColor;
#endif
@@ -205,6 +279,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-dasharray"><code>line-dasharray</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSNumber *> *> *lineDashPattern;
@@ -219,6 +299,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineGapWidth;
@@ -233,6 +329,22 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOffset;
@@ -242,12 +354,34 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineOpacity;
/**
Name of image in style images to use for drawing image lines. For seamless
patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *linePattern;
@@ -264,6 +398,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
#else
@@ -279,6 +420,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate"><code>line-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslation;
#endif
@@ -298,6 +446,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-line-translate-anchor"><code>line-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *lineTranslationAnchor;
@@ -311,6 +465,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineWidth;
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 13408d426c..80b1e907e6 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -66,7 +66,7 @@ namespace mbgl {
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -119,8 +119,9 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -150,7 +151,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)lineCap {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineCap() ?: self.rawLayer->getDefaultLineCap();
+ auto propertyValue = self.rawLayer->getLineCap();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(self.rawLayer->getDefaultLineCap());
+ }
return MGLStyleValueTransformer<mbgl::style::LineCapType, NSValue *, mbgl::style::LineCapType, MGLLineCap>().toEnumStyleValue(propertyValue);
}
@@ -164,35 +168,44 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)lineJoin {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineJoin() ?: self.rawLayer->getDefaultLineJoin();
+ auto propertyValue = self.rawLayer->getLineJoin();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(self.rawLayer->getDefaultLineJoin());
+ }
return MGLStyleValueTransformer<mbgl::style::LineJoinType, NSValue *, mbgl::style::LineJoinType, MGLLineJoin>().toEnumStyleValue(propertyValue);
}
- (void)setLineMiterLimit:(MGLStyleValue<NSNumber *> *)lineMiterLimit {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineMiterLimit);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineMiterLimit);
self.rawLayer->setLineMiterLimit(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineMiterLimit {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineMiterLimit() ?: self.rawLayer->getDefaultLineMiterLimit();
+ auto propertyValue = self.rawLayer->getLineMiterLimit();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineMiterLimit());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setLineRoundLimit:(MGLStyleValue<NSNumber *> *)lineRoundLimit {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineRoundLimit);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineRoundLimit);
self.rawLayer->setLineRoundLimit(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineRoundLimit {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineRoundLimit() ?: self.rawLayer->getDefaultLineRoundLimit();
+ auto propertyValue = self.rawLayer->getLineRoundLimit();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineRoundLimit());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -201,29 +214,35 @@ namespace mbgl {
- (void)setLineBlur:(MGLStyleValue<NSNumber *> *)lineBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineBlur);
self.rawLayer->setLineBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineBlur {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineBlur() ?: self.rawLayer->getDefaultLineBlur();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getLineBlur();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineBlur());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineColor:(MGLStyleValue<MGLColor *> *)lineColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(lineColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(lineColor);
self.rawLayer->setLineColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)lineColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineColor() ?: self.rawLayer->getDefaultLineColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getLineColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineDashPattern:(MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
@@ -236,7 +255,10 @@ namespace mbgl {
- (MGLStyleValue<NSArray<NSNumber *> *> *)lineDashPattern {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineDasharray() ?: self.rawLayer->getDefaultLineDasharray();
+ auto propertyValue = self.rawLayer->getLineDasharray();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(self.rawLayer->getDefaultLineDasharray());
+ }
return MGLStyleValueTransformer<std::vector<float>, NSArray<NSNumber *> *, float>().toStyleValue(propertyValue);
}
@@ -250,43 +272,52 @@ namespace mbgl {
- (void)setLineGapWidth:(MGLStyleValue<NSNumber *> *)lineGapWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineGapWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineGapWidth);
self.rawLayer->setLineGapWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineGapWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineGapWidth() ?: self.rawLayer->getDefaultLineGapWidth();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getLineGapWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineGapWidth());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineOffset:(MGLStyleValue<NSNumber *> *)lineOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOffset);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineOffset);
self.rawLayer->setLineOffset(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineOffset {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineOffset() ?: self.rawLayer->getDefaultLineOffset();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getLineOffset();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOffset());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineOpacity:(MGLStyleValue<NSNumber *> *)lineOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineOpacity);
self.rawLayer->setLineOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineOpacity() ?: self.rawLayer->getDefaultLineOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getLineOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLinePattern:(MGLStyleValue<NSString *> *)linePattern {
@@ -299,21 +330,27 @@ namespace mbgl {
- (MGLStyleValue<NSString *> *)linePattern {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLinePattern() ?: self.rawLayer->getDefaultLinePattern();
+ auto propertyValue = self.rawLayer->getLinePattern();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultLinePattern());
+ }
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
- (void)setLineTranslation:(MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(lineTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(lineTranslation);
self.rawLayer->setLineTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)lineTranslation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineTranslate() ?: self.rawLayer->getDefaultLineTranslate();
+ auto propertyValue = self.rawLayer->getLineTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultLineTranslate());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -334,7 +371,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)lineTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineTranslateAnchor() ?: self.rawLayer->getDefaultLineTranslateAnchor();
+ auto propertyValue = self.rawLayer->getLineTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultLineTranslateAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLLineTranslationAnchor>().toEnumStyleValue(propertyValue);
}
@@ -348,14 +388,17 @@ namespace mbgl {
- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(lineWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineWidth);
self.rawLayer->setLineWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)lineWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getLineWidth() ?: self.rawLayer->getDefaultLineWidth();
+ auto propertyValue = self.rawLayer->getLineWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineWidth());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLMapCamera.h b/platform/darwin/src/MGLMapCamera.h
index 3d492656af..7ce5927d1d 100644
--- a/platform/darwin/src/MGLMapCamera.h
+++ b/platform/darwin/src/MGLMapCamera.h
@@ -32,9 +32,9 @@ MGL_EXPORT
+ (instancetype)camera;
/**
- Returns a new camera using based on information about the camera’s viewpoint
+ Returns a new camera based on information about the camera’s viewpoint
and focus point.
-
+
@param centerCoordinate The geographic coordinate on which the map should be
centered.
@param eyeCoordinate The geometric coordinate at which the camera should be
@@ -49,7 +49,7 @@ MGL_EXPORT
/**
Returns a new camera with the given distance, pitch, and heading.
-
+
@param centerCoordinate The geographic coordinate on which the map should be
centered.
@param distance The straight-line distance from the viewpoint to the
@@ -67,6 +67,20 @@ MGL_EXPORT
pitch:(CGFloat)pitch
heading:(CLLocationDirection)heading;
+/**
+ Returns a Boolean value indicating whether the given camera is functionally
+ equivalent to the receiver.
+
+ Unlike `-isEqual:`, this method returns `YES` if the difference between the
+ coordinates, altitudes, pitches, or headings of the two camera objects is
+ negligible.
+
+ @param otherCamera The camera with which to compare the receiver.
+ @return A Boolean value indicating whether the two cameras are functionally
+ equivalent.
+ */
+- (BOOL)isEqualToMapCamera:(MGLMapCamera *)otherCamera;
+
@end
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLMapCamera.mm b/platform/darwin/src/MGLMapCamera.mm
index fafbefd17a..613124da66 100644
--- a/platform/darwin/src/MGLMapCamera.mm
+++ b/platform/darwin/src/MGLMapCamera.mm
@@ -2,6 +2,11 @@
#include <mbgl/util/projection.hpp>
+BOOL MGLEqualFloatWithAccuracy(CGFloat left, CGFloat right, CGFloat accuracy)
+{
+ return MAX(left, right) - MIN(left, right) <= accuracy;
+}
+
@implementation MGLMapCamera
+ (BOOL)supportsSecureCoding
@@ -20,16 +25,16 @@
{
mbgl::LatLng centerLatLng = mbgl::LatLng(centerCoordinate.latitude, centerCoordinate.longitude);
mbgl::LatLng eyeLatLng = mbgl::LatLng(eyeCoordinate.latitude, eyeCoordinate.longitude);
-
+
mbgl::ProjectedMeters centerMeters = mbgl::Projection::projectedMetersForLatLng(centerLatLng);
mbgl::ProjectedMeters eyeMeters = mbgl::Projection::projectedMetersForLatLng(eyeLatLng);
CLLocationDirection heading = std::atan((centerMeters.northing - eyeMeters.northing) /
(centerMeters.easting - eyeMeters.easting));
-
+
double groundDistance = std::hypot(centerMeters.northing - eyeMeters.northing,
centerMeters.easting - eyeMeters.easting);
CGFloat pitch = std::atan(eyeAltitude / groundDistance);
-
+
return [[self alloc] initWithCenterCoordinate:centerCoordinate
altitude:eyeAltitude
pitch:pitch
@@ -108,7 +113,7 @@
{
return YES;
}
-
+
MGLMapCamera *otherCamera = other;
return (_centerCoordinate.latitude == otherCamera.centerCoordinate.latitude
&& _centerCoordinate.longitude == otherCamera.centerCoordinate.longitude
@@ -116,6 +121,20 @@
&& _pitch == otherCamera.pitch && _heading == otherCamera.heading);
}
+- (BOOL)isEqualToMapCamera:(MGLMapCamera *)otherCamera
+{
+ if (otherCamera == self)
+ {
+ return YES;
+ }
+
+ return (MGLEqualFloatWithAccuracy(_centerCoordinate.latitude, otherCamera.centerCoordinate.latitude, 1e-6)
+ && MGLEqualFloatWithAccuracy(_centerCoordinate.longitude, otherCamera.centerCoordinate.longitude, 1e-6)
+ && MGLEqualFloatWithAccuracy(_altitude, otherCamera.altitude, 1e-6)
+ && MGLEqualFloatWithAccuracy(_pitch, otherCamera.pitch, 1)
+ && MGLEqualFloatWithAccuracy(_heading, otherCamera.heading, 1));
+}
+
- (NSUInteger)hash
{
return (@(_centerCoordinate.latitude).hash + @(_centerCoordinate.longitude).hash
diff --git a/platform/darwin/src/MGLMultiPoint.h b/platform/darwin/src/MGLMultiPoint.h
index 31ab5744a3..ca08e5405a 100644
--- a/platform/darwin/src/MGLMultiPoint.h
+++ b/platform/darwin/src/MGLMultiPoint.h
@@ -9,12 +9,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
The `MGLMultiPoint` class is an abstract superclass used to define shapes
composed of multiple vertices.
-
+
You do not create instances of this class directly. Instead, you create
instances of the `MGLPolyline` or `MGLPolygon` classes. However, you can use
the method and properties of this class to access information about the
vertices of the line or polygon.
-
+
Do not confuse `MGLMultiPoint` with `MGLPointCollection`, which represents a
collection of related but disconnected points.
*/
@@ -23,7 +23,7 @@ MGL_EXPORT
/**
The array of vertices associated with the shape.
-
+
This C array is a pointer to a structure inside the multipoint object, which
may have a lifetime shorter than the multipoint object and will certainly not
have a longer lifetime. Therefore, you should copy the C array if it needs to
@@ -36,7 +36,7 @@ MGL_EXPORT
/**
Retrieves the vertices of part of the shape.
-
+
@param coords On input, you must provide a C array of `CLLocationCoordinate2D`
structures large enough to hold the desired number of coordinates. On
output, this structure contains the requested coordinate data.
@@ -50,7 +50,7 @@ MGL_EXPORT
/**
Sets the shape’s vertices to the given C array of vertices.
-
+
@param coords The array of coordinates defining the shape. The data in this
array is copied to the shape’s `coordinates` property.
@param count The number of coordinates from the `coords` array.
@@ -60,7 +60,7 @@ MGL_EXPORT
/**
Inserts the given vertices into the shape. If the shape is currently visible on
the map, it is redrawn immediately.
-
+
@param coords The array of coordinates to insert into the shape. The data in
this array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
@@ -72,7 +72,7 @@ MGL_EXPORT
/**
Appends the given vertices to the shape. If the shape is currently visible on
the map, it is redrawn immediately.
-
+
@param coords The array of coordinates to add to the shape. The data in this
array is copied to the shape’s `coordinates` property.
@param count The number of items in the `coords` array.
@@ -83,15 +83,15 @@ MGL_EXPORT
Replaces the vertices at the given range in the shape with the same number of
vertices from a given C array. If the shape is currently visible on the map, it
is redrawn immediately.
-
+
The number of coordinates in `coords` must be equal to the length of `range`.
If you want to insert or delete one or more vertices, use the
`-replaceCoordinatesInRange:withCoordinates:count:` method.
-
+
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised. If you want to append new vertices to the shape,
use the `-appendCoordinates:count:` method.
-
+
@param range The range of vertices to replace. The `location` field indicates
the first vertex you are replacing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
@@ -105,15 +105,15 @@ MGL_EXPORT
Replaces the vertices at the given range in the shape with the specified number
of vertices from a given C array. If the shape is currently visible on the map,
it is redrawn immediately.
-
+
If `count` is greater than the `length` field of `range`, some vertices will
effectively be inserted into the shape. On the other hand, if `count` is less
than the `length` field of `range`, some vertices will effectively be removed.
-
+
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised. If you want to append new vertices to the shape,
use the `-appendCoordinates:count:` method.
-
+
@param range The range of vertices to replace. The `location` field indicates
the first vertex you are replacing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
@@ -130,10 +130,10 @@ MGL_EXPORT
/**
Removes the vertices at the given range from the shape. If the shape is
currently visible on the map, it is redrawn immediately.
-
+
If `range` extends beyond the shape’s `coordinates` property, an
`NSRangeException` is raised.
-
+
@param range The range of vertices to remove. The `location` field indicates
the first vertex you are removing, with `0` being the first vertex, `1`
being the second vertex, and so on. The `length` field indicates the number
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 3b03b78ca6..8e8c5be304 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -44,7 +44,7 @@
{
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPoint class]]) return NO;
-
+
MGLMultiPoint *otherMultipoint = other;
return ([super isEqual:otherMultipoint]
&& _coordinates == otherMultipoint->_coordinates);
@@ -97,7 +97,7 @@
[NSException raise:NSInvalidArgumentException
format:@"A multipoint must have at least one vertex."];
}
-
+
[self willChangeValueForKey:@"coordinates"];
_coordinates = { coords, coords + count };
_bounds = {};
@@ -108,13 +108,13 @@
if (!count) {
return;
}
-
+
if (index > _coordinates.size()) {
[NSException raise:NSRangeException
format:@"Invalid index %lu for existing coordinate count %ld",
(unsigned long)index, (unsigned long)[self pointCount]];
}
-
+
[self willChangeValueForKey:@"coordinates"];
_coordinates.insert(_coordinates.begin() + index, count, *coords);
_bounds = {};
@@ -135,7 +135,7 @@
if (!count && !range.length) {
return;
}
-
+
if (NSMaxRange(range) > _coordinates.size()) {
[NSException raise:NSRangeException
format:@"Invalid range %@ for existing coordinate count %ld",
diff --git a/platform/darwin/src/MGLNetworkConfiguration.h b/platform/darwin/src/MGLNetworkConfiguration.h
index 88fb07e111..644291ee13 100644
--- a/platform/darwin/src/MGLNetworkConfiguration.h
+++ b/platform/darwin/src/MGLNetworkConfiguration.h
@@ -3,11 +3,11 @@
NS_ASSUME_NONNULL_BEGIN
/**
- The MGLNetworkConfiguration object provides a global way to set a base API URL for
+ The MGLNetworkConfiguration object provides a global way to set a base API URL for
retrieval of map data, styles, and other resources.
-
- Currently, MGLNetworkConfiguration is private API in code but is able to be used
- by any applications via the `MGLMapboxAPIBaseURL` dictionary key in the
+
+ Currently, MGLNetworkConfiguration is private API in code but is able to be used
+ by any applications via the `MGLMapboxAPIBaseURL` dictionary key in the
application's `Info.plist`.
*/
@interface MGLNetworkConfiguration : NSObject
@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
/// Returns the shared instance of the `MGLNetworkConfiguration` class.
+ (instancetype)sharedManager;
-/// The current API base URL. If `nil`, the Mapbox default base API URL is in use.
+/// The current API base URL. If `nil`, the Mapbox default base API URL is in use.
@property (atomic, nullable) NSURL *apiBaseURL;
@end
diff --git a/platform/darwin/src/MGLOfflinePack.h b/platform/darwin/src/MGLOfflinePack.h
index 8436434e68..0b2db35b1a 100644
--- a/platform/darwin/src/MGLOfflinePack.h
+++ b/platform/darwin/src/MGLOfflinePack.h
@@ -11,20 +11,20 @@ NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM (NSInteger, MGLOfflinePackState) {
/**
It is unknown whether the pack is inactive, active, or complete.
-
+
This is the initial state of a pack. The state of a pack becomes known by
the time the shared `MGLOfflineStorage` object sends the first
`MGLOfflinePackProgressChangedNotification` about the pack. For inactive
packs, you must explicitly request a progress update using the
`-[MGLOfflinePack requestProgress]` method.
-
+
An invalid pack always has a state of `MGLOfflinePackStateInvalid`, never
`MGLOfflinePackStateUnknown`.
*/
MGLOfflinePackStateUnknown = 0,
/**
The pack is incomplete and is not currently downloading.
-
+
This is the initial state of a pack that is created using the
`-[MGLOfflineStorage addPackForRegion:withContext:completionHandler:]`
method, as well as after the `-[MGLOfflinePack suspend]` method is
@@ -33,7 +33,7 @@ typedef NS_ENUM (NSInteger, MGLOfflinePackState) {
MGLOfflinePackStateInactive = 1,
/**
The pack is incomplete and is currently downloading.
-
+
This is the state of a pack after the `-[MGLOfflinePack resume]` method is
called.
*/
@@ -77,7 +77,7 @@ typedef struct MGLOfflinePackProgress {
/**
The minimum number of resources that must be downloaded in order to view
the pack’s full region without any omissions.
-
+
At the beginning of a download, this count is a lower bound; the number of
expected resources may increase as the download progresses.
*/
@@ -85,7 +85,7 @@ typedef struct MGLOfflinePackProgress {
/**
The maximum number of resources that must be downloaded in order to view
the pack’s full region without any omissions.
-
+
At the beginning of a download, when the exact number of required resources
is unknown, this field is set to `UINT64_MAX`. Thus this count is always an
upper bound.
@@ -96,7 +96,7 @@ typedef struct MGLOfflinePackProgress {
/**
An `MGLOfflinePack` represents a collection of resources necessary for viewing
a region offline to a local database.
-
+
To create an instance of `MGLOfflinePack`, use the
`+[MGLOfflineStorage addPackForRegion:withContext:completionHandler:]` method.
A pack created using `-[MGLOfflinePack init]` is immediately invalid.
@@ -111,7 +111,7 @@ MGL_EXPORT
/**
Arbitrary data stored alongside the downloaded resources.
-
+
The context typically holds application-specific information for identifying
the pack, such as a user-selected name.
*/
@@ -119,7 +119,7 @@ MGL_EXPORT
/**
The pack’s current state.
-
+
The state of an inactive or completed pack is computed lazily and is set to
`MGLOfflinePackStateUnknown` by default. To request the pack’s status, use the
`-requestProgress` method. To get notified when the state becomes known and
@@ -132,7 +132,7 @@ MGL_EXPORT
/**
The pack’s current progress.
-
+
The progress of an inactive or completed pack is computed lazily, and all its
fields are set to 0 by default. To request the pack’s progress, use the
`-requestProgress` method. To get notified when the progress becomes
@@ -145,33 +145,33 @@ MGL_EXPORT
/**
Resumes downloading if the pack is inactive.
-
+
When a pack resumes after being suspended, it may begin by iterating over the
already downloaded resources. As a result, the `progress` structure’s
`countOfResourcesCompleted` field may revert to 0 before rapidly returning to
the level of progress at the time the pack was suspended.
-
+
To temporarily suspend downloading, call the `-suspend` method.
*/
- (void)resume;
/**
Temporarily stops downloading if the pack is active.
-
+
A pack suspends asynchronously, so some network requests may be sent after this
method is called. Regardless, the `progress` property will not be updated until
`-resume` is called.
-
+
If the pack previously reached a higher level of progress before being
suspended, it may wait to suspend until it returns to that level.
-
+
To resume downloading, call the `-resume` method.
*/
- (void)suspend;
/**
Request an asynchronous update to the pack’s `state` and `progress` properties.
-
+
The state and progress of an inactive or completed pack are computed lazily. If
you need the state or progress of a pack whose `state` property is currently
set to `MGLOfflinePackStateUnknown`, observe KVO change notifications on this
diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm
index 1f2fd95f2b..60a7b55531 100644
--- a/platform/darwin/src/MGLOfflinePack.mm
+++ b/platform/darwin/src/MGLOfflinePack.mm
@@ -4,11 +4,13 @@
#import "MGLOfflineRegion_Private.h"
#import "MGLTilePyramidOfflineRegion.h"
+#import "NSValue+MGLAdditions.h"
+
#include <mbgl/storage/default_file_source.hpp>
/**
Assert that the current offline pack is valid.
-
+
This macro should be used at the beginning of any public-facing instance method
of `MGLOfflinePack`. For private methods, an assertion is more appropriate.
*/
@@ -26,18 +28,17 @@
class MBGLOfflineRegionObserver : public mbgl::OfflineRegionObserver {
public:
MBGLOfflineRegionObserver(MGLOfflinePack *pack_) : pack(pack_) {}
-
+
void statusChanged(mbgl::OfflineRegionStatus status) override;
void responseError(mbgl::Response::Error error) override;
void mapboxTileCountLimitExceeded(uint64_t limit) override;
-
+
private:
__weak MGLOfflinePack *pack = nullptr;
};
@interface MGLOfflinePack ()
-@property (nonatomic, weak, nullable) id <MGLOfflinePackDelegate> delegate;
@property (nonatomic, nullable, readwrite) mbgl::OfflineRegion *mbglOfflineRegion;
@property (nonatomic, readwrite) MGLOfflinePackProgress progress;
@@ -59,7 +60,7 @@ private:
if (self = [super init]) {
_mbglOfflineRegion = region;
_state = MGLOfflinePackStateUnknown;
-
+
mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique<MBGLOfflineRegionObserver>(self));
}
@@ -72,7 +73,7 @@ private:
- (id <MGLOfflineRegion>)region {
MGLAssertOfflinePackIsValid();
-
+
const mbgl::OfflineRegionDefinition &regionDefinition = _mbglOfflineRegion->getDefinition();
NSAssert([MGLTilePyramidOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLTilePyramidOfflineRegion should conform to MGLOfflineRegion_Private.");
return [(id <MGLOfflineRegion_Private>)[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:regionDefinition];
@@ -80,35 +81,35 @@ private:
- (NSData *)context {
MGLAssertOfflinePackIsValid();
-
+
const mbgl::OfflineRegionMetadata &metadata = _mbglOfflineRegion->getMetadata();
return [NSData dataWithBytes:&metadata[0] length:metadata.size()];
}
- (void)resume {
MGLAssertOfflinePackIsValid();
-
+
self.state = MGLOfflinePackStateActive;
-
+
mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active);
}
- (void)suspend {
MGLAssertOfflinePackIsValid();
-
+
if (self.state == MGLOfflinePackStateActive) {
self.state = MGLOfflinePackStateInactive;
_isSuspending = YES;
}
-
+
mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive);
}
- (void)invalidate {
NSAssert(_state != MGLOfflinePackStateInvalid, @"Cannot invalidate an already invalid offline pack.");
-
+
self.state = MGLOfflinePackStateInvalid;
mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr);
@@ -123,9 +124,9 @@ private:
NSAssert(_state == MGLOfflinePackStateInvalid, @"A valid MGLOfflinePack has no mbgl::OfflineRegion.");
return;
}
-
+
NSAssert(_state != MGLOfflinePackStateInvalid, @"Cannot change the state of an invalid offline pack.");
-
+
if (!_isSuspending || state != MGLOfflinePackStateActive) {
_isSuspending = NO;
_state = state;
@@ -134,9 +135,9 @@ private:
- (void)requestProgress {
MGLAssertOfflinePackIsValid();
-
+
mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource];
-
+
__weak MGLOfflinePack *weakSelf = self;
mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](__unused std::exception_ptr exception, mbgl::optional<mbgl::OfflineRegionStatus> status) {
if (status) {
@@ -151,21 +152,21 @@ private:
- (void)offlineRegionStatusDidChange:(mbgl::OfflineRegionStatus)status {
NSAssert(_state != MGLOfflinePackStateInvalid, @"Cannot change update progress of an invalid offline pack.");
-
+
switch (status.downloadState) {
case mbgl::OfflineRegionDownloadState::Inactive:
self.state = status.complete() ? MGLOfflinePackStateComplete : MGLOfflinePackStateInactive;
break;
-
+
case mbgl::OfflineRegionDownloadState::Active:
self.state = MGLOfflinePackStateActive;
break;
}
-
+
if (_isSuspending) {
return;
}
-
+
MGLOfflinePackProgress progress;
progress.countOfResourcesCompleted = status.completedResourceCount;
progress.countOfBytesCompleted = status.completedResourceSize;
@@ -174,8 +175,30 @@ private:
progress.countOfResourcesExpected = status.requiredResourceCount;
progress.maximumResourcesExpected = status.requiredResourceCountIsPrecise ? status.requiredResourceCount : UINT64_MAX;
self.progress = progress;
-
- [self.delegate offlinePack:self progressDidChange:progress];
+
+ NSDictionary *userInfo = @{MGLOfflinePackUserInfoKeyState: @(self.state),
+ MGLOfflinePackUserInfoKeyProgress: [NSValue valueWithMGLOfflinePackProgress:progress]};
+
+ NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
+ [noteCenter postNotificationName:MGLOfflinePackProgressChangedNotification
+ object:self
+ userInfo:userInfo];
+}
+
+- (void)didReceiveError:(NSError *)error {
+ NSDictionary *userInfo = @{ MGLOfflinePackUserInfoKeyError: error };
+ NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
+ [noteCenter postNotificationName:MGLOfflinePackErrorNotification
+ object:self
+ userInfo:userInfo];
+}
+
+- (void)didReceiveMaximumAllowedMapboxTiles:(uint64_t)limit {
+ NSDictionary *userInfo = @{ MGLOfflinePackUserInfoKeyMaximumCount: @(limit) };
+ NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
+ [noteCenter postNotificationName:MGLOfflinePackMaximumMapboxTilesReachedNotification
+ object:self
+ userInfo:userInfo];
}
NSError *MGLErrorFromResponseError(mbgl::Response::Error error) {
@@ -184,15 +207,15 @@ NSError *MGLErrorFromResponseError(mbgl::Response::Error error) {
case mbgl::Response::Error::Reason::NotFound:
errorCode = MGLErrorCodeNotFound;
break;
-
+
case mbgl::Response::Error::Reason::Server:
errorCode = MGLErrorCodeBadServerResponse;
break;
-
+
case mbgl::Response::Error::Reason::Connection:
errorCode = MGLErrorCodeConnectionFailed;
break;
-
+
default:
break;
}
@@ -211,12 +234,12 @@ void MBGLOfflineRegionObserver::statusChanged(mbgl::OfflineRegionStatus status)
void MBGLOfflineRegionObserver::responseError(mbgl::Response::Error error) {
dispatch_async(dispatch_get_main_queue(), ^{
- [pack.delegate offlinePack:pack didReceiveError:MGLErrorFromResponseError(error)];
+ [pack didReceiveError:MGLErrorFromResponseError(error)];
});
}
void MBGLOfflineRegionObserver::mapboxTileCountLimitExceeded(uint64_t limit) {
dispatch_async(dispatch_get_main_queue(), ^{
- [pack.delegate offlinePack:pack didReceiveMaximumAllowedMapboxTiles:limit];
+ [pack didReceiveMaximumAllowedMapboxTiles:limit];
});
}
diff --git a/platform/darwin/src/MGLOfflinePack_Private.h b/platform/darwin/src/MGLOfflinePack_Private.h
index 95d8ba4323..8a63152dca 100644
--- a/platform/darwin/src/MGLOfflinePack_Private.h
+++ b/platform/darwin/src/MGLOfflinePack_Private.h
@@ -4,19 +4,8 @@
NS_ASSUME_NONNULL_BEGIN
-@protocol MGLOfflinePackDelegate;
-
@interface MGLOfflinePack (Private)
-/**
- The pack’s delegate.
-
- You can use the offline pack delegate to be notified of any changes in the
- pack’s progress and of any errors while downloading. For more information, see
- the `MGLOfflinePackDelegate` documentation.
- */
-@property (nonatomic, weak, nullable) id <MGLOfflinePackDelegate> delegate;
-
@property (nonatomic, nullable) mbgl::OfflineRegion *mbglOfflineRegion;
@property (nonatomic, readwrite) MGLOfflinePackState state;
@@ -31,47 +20,4 @@ NS_ASSUME_NONNULL_BEGIN
@end
-/**
- The `MGLOfflinePackDelegate` protocol defines methods that a delegate of an
- `MGLOfflinePack` object can optionally implement to be notified of any changes
- in the pack’s download progress and of any errors while downloading.
- */
-@protocol MGLOfflinePackDelegate <NSObject>
-
-/**
- Sent whenever the pack’s state or download progress changes. Every change to a
- field in the `progress` property corresponds to an invocation of this method.
-
- @param pack The pack whose state of progress changed.
- @param progress The updated progress. To get the updated state, refer to the
- `state` property.
- */
-- (void)offlinePack:(MGLOfflinePack *)pack progressDidChange:(MGLOfflinePackProgress)progress;
-
-/**
- Sent whenever the pack encounters an error while downloading.
-
- Download errors may be recoverable. For example, this pack’s implementation may
- attempt to re-request failed resources based on an exponential backoff
- strategy or upon the restoration of network access.
-
- @param pack The pack that encountered an error.
- @param error A download error. For a list of possible error codes, see
- `MGLErrorCode`.
- */
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveError:(NSError *)error;
-
-/**
- Sent when the maximum number of Mapbox-hosted tiles has been downloaded and
- stored on the current device.
-
- Once this limit is reached, no instance of `MGLOfflinePack` can download
- additional tiles from Mapbox APIs until already downloaded tiles are removed by
- calling the `-[MGLOfflineStorage removePack:withCompletionHandler:]` method.
- Contact your Mapbox sales representative to have the limit raised.
- */
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount;
-
-@end
-
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLOfflineRegion_Private.h b/platform/darwin/src/MGLOfflineRegion_Private.h
index 22106987d0..b1dec8dd64 100644
--- a/platform/darwin/src/MGLOfflineRegion_Private.h
+++ b/platform/darwin/src/MGLOfflineRegion_Private.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Initializes and returns an offline region backed by the given C++ region
definition object.
-
+
@param definition A reference to an offline region definition backing the
offline region.
*/
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 9125c5341e..16f134adb1 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -7,6 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
@class MGLOfflinePack;
@protocol MGLOfflineRegion;
+@protocol MGLOfflineStorageDelegate;
/**
Posted by the shared `MGLOfflineStorage` object when an `MGLOfflinePack`
@@ -14,14 +15,14 @@ NS_ASSUME_NONNULL_BEGIN
downloaded or because the pack discovers during the download that more
resources are required for offline viewing. This notification is posted
whenever any field in the `progress` property changes.
-
+
The `object` is the `MGLOfflinePack` object whose progress changed. The
`userInfo` dictionary contains the pack’s current state in the
`MGLOfflinePackStateUserInfoKey` key and details about the pack’s current
progress in the `MGLOfflinePackProgressUserInfoKey` key. You may also consult
the `MGLOfflinePack.state` and `MGLOfflinePack.progress` properties, which
provide the same values.
-
+
If you only need to observe changes in a particular pack’s progress, you can
alternatively observe KVO change notifications to the pack’s `progress` key
path.
@@ -34,7 +35,7 @@ extern MGL_EXPORT const NSNotificationName MGLOfflinePackProgressChangedNotifica
may not warrant the user’s attention. For example, the pack’s implementation
may attempt to re-request failed resources based on an exponential backoff
strategy or upon the restoration of network access.
-
+
The `object` is the `MGLOfflinePack` object that encountered the error. The
`userInfo` dictionary contains the error object in the
`MGLOfflinePackErrorUserInfoKey` key.
@@ -44,11 +45,11 @@ extern MGL_EXPORT const NSNotificationName MGLOfflinePackErrorNotification;
/**
Posted by the shared `MGLOfflineStorage` object when the maximum number of
Mapbox-hosted tiles has been downloaded and stored on the current device.
-
+
The `object` is the `MGLOfflinePack` object that reached the tile limit in the
course of downloading. The `userInfo` dictionary contains the tile limit in the
`MGLOfflinePackMaximumCountUserInfoKey` key.
-
+
Once this limit is reached, no instance of `MGLOfflinePack` can download
additional tiles from Mapbox APIs until already downloaded tiles are removed by
calling the `-[MGLOfflineStorage removePack:withCompletionHandler:]` method.
@@ -107,10 +108,10 @@ extern MGL_EXPORT NSString * const MGLOfflinePackMaximumCountUserInfoKey __attri
/**
A block to be called once an offline pack has been completely created and
added.
-
+
An application typically calls the `-resume` method on the pack inside this
completion handler to begin the download.
-
+
@param pack Contains a pointer to the newly added pack, or `nil` if there was
an error creating or adding the pack.
@param error Contains a pointer to an error object (if any) indicating why the
@@ -121,17 +122,41 @@ typedef void (^MGLOfflinePackAdditionCompletionHandler)(MGLOfflinePack * _Nullab
/**
A block to be called once an offline pack has been completely invalidated and
removed.
-
+
Avoid any references to the pack inside this completion handler: by the time
this completion handler is executed, the pack has become invalid, and any
messages passed to it will raise an exception.
-
+
@param error Contains a pointer to an error object (if any) indicating why the
pack could not be invalidated or removed.
*/
typedef void (^MGLOfflinePackRemovalCompletionHandler)(NSError * _Nullable error);
/**
+ The type of resource that is requested.
+ */
+typedef NS_ENUM(NSUInteger, MGLResourceKind) {
+ /** Unknown type */
+ MGLResourceKindUnknown,
+ /** Style sheet JSON file */
+ MGLResourceKindStyle,
+ /** TileJSON file as specified in https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sources */
+ MGLResourceKindSource,
+ /** A vector or raster tile as described in the style sheet at
+ https://www.mapbox.com/mapbox-gl-js/style-spec/#sources */
+ MGLResourceKindTile,
+ /** Signed distance field glyphs for text rendering. These are the URLs specified in the style
+ in https://www.mapbox.com/mapbox-gl-js/style-spec/#root-glyphs */
+ MGLResourceKindGlyphs,
+ /** Image part of a sprite sheet. It is constructed of the prefix in
+ https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a PNG file extension. */
+ MGLResourceKindSpriteImage,
+ /** JSON part of a sprite sheet. It is constructed of the prefix in
+ https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a JSON file extension. */
+ MGLResourceKindSpriteJSON,
+};
+
+/**
MGLOfflineStorage implements a singleton (shared object) that manages offline
packs. All of this class’s instance methods are asynchronous, reflecting the
fact that offline resources are stored in a database. The shared object
@@ -145,15 +170,29 @@ MGL_EXPORT
*/
+ (instancetype)sharedOfflineStorage;
+#pragma mark - Accessing the Delegate
+
+/**
+ The receiver’s delegate.
+
+ An offline storage object sends messages to its delegate to allow it to
+ transform URLs before they are requested from the internet. This can be used
+ add or remove custom parameters, or reroute certain requests to other servers
+ or endpoints.
+ */
+@property(nonatomic, weak, nullable) IBOutlet id<MGLOfflineStorageDelegate> delegate;
+
+#pragma mark - Managing Offline Packs
+
/**
An array of all known offline packs, in the order in which they were created.
-
+
This property is set to `nil`, indicating that the receiver does not yet know
the existing packs, for an undefined amount of time starting from the moment
the shared offline storage object is initialized until the packs are fetched
from the database. After that point, this property is always non-nil, but it
may be empty to indicate that no packs are present.
-
+
To detect when the shared offline storage object has finished loading its
`packs` property, observe KVO change notifications on the `packs` key path.
The initial load results in an `NSKeyValueChangeSetting` change.
@@ -163,19 +202,19 @@ MGL_EXPORT
/**
Creates and registers an offline pack that downloads the resources needed to
use the given region offline.
-
+
The resulting pack is added to the shared offline storage object’s `packs`
property, then the `completion` block is executed with that pack passed in.
-
+
The pack has an initial state of `MGLOfflinePackStateInactive`. To begin
downloading resources, call `-[MGLOfflinePack resume]` on the pack from within
the completion handler. To monitor download progress, add an observer for
`MGLOfflinePackProgressChangedNotification`s about that pack.
-
+
To detect when any call to this method results in a new pack, observe KVO
change notifications on the shared offline storage object’s `packs` key path.
Additions to that array result in an `NSKeyValueChangeInsertion` change.
-
+
@param region A region to download.
@param context Arbitrary data to store alongside the downloaded resources.
@param completion The completion handler to call once the pack has been added.
@@ -186,17 +225,17 @@ MGL_EXPORT
/**
Unregisters the given offline pack and allows resources that are no longer
required by any remaining packs to be potentially freed.
-
+
As soon as this method is called on a pack, the pack becomes invalid; any
attempt to send it a message will result in an exception being thrown. If an
error occurs and the pack cannot be removed, do not attempt to reuse the pack
object. Instead, if you need continued access to the pack, suspend all packs
and use the `-reloadPacks` method to obtain valid pointers to all the packs.
-
+
To detect when any call to this method results in a pack being removed, observe
KVO change notifications on the shared offline storage object’s `packs` key
path. Removals from that array result in an `NSKeyValueChangeRemoval` change.
-
+
When you remove an offline pack, any resources that are required by that pack,
but not other packs, become eligible for deletion from offline storage. Because
the backing store used for offline storage is also used as a general purpose
@@ -216,9 +255,9 @@ MGL_EXPORT
`packs` property change, even if the underlying data for these packs has not
changed. If this method is called while a pack is actively downloading, the
behavior is undefined.
-
+
You typically do not need to call this method.
-
+
To detect when the shared offline storage object has finished reloading its
`packs` property, observe KVO change notifications on the `packs` key path.
A reload results in an `NSKeyValueChangeSetting` change.
@@ -228,12 +267,12 @@ MGL_EXPORT
/**
Sets the maximum number of Mapbox-hosted tiles that may be downloaded and
stored on the current device.
-
+
Once this limit is reached, an
`MGLOfflinePackMaximumMapboxTilesReachedNotification` is posted for every
attempt to download additional tiles until already downloaded tiles are removed
by calling the `-removePack:withCompletionHandler:` method.
-
+
@note The <a href="https://www.mapbox.com/tos/">Mapbox Terms of Service</a>
prohibits changing or bypassing this limit without permission from Mapbox.
Contact your Mapbox sales representative to have the limit raised.
@@ -242,7 +281,7 @@ MGL_EXPORT
/**
The cumulative size, measured in bytes, of all downloaded resources on disk.
-
+
The returned value includes all resources, including tiles, whether downloaded
as part of an offline pack or due to caching during normal use of `MGLMapView`.
*/
@@ -250,4 +289,25 @@ MGL_EXPORT
@end
+/**
+ The `MGLOfflineStorageDelegate` protocol defines methods that a delegate of an
+ `MGLOfflineStorage` object can optionally implement to transform various types
+ of URLs before downloading them via the internet.
+ */
+@protocol MGLOfflineStorageDelegate <NSObject>
+
+/**
+ Sent whenever a URL needs to be transformed.
+
+ @param storage The storage object processing the download.
+ @param kind The kind of URL to be transformed.
+ @param url The original URL to be transformed.
+ @return A URL that will now be downloaded.
+ */
+- (NSURL *)offlineStorage:(MGLOfflineStorage *)storage
+ URLForResourceOfKind:(MGLResourceKind)kind
+ withURL:(NSURL *)url;
+
+@end
+
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 10acc58b25..9cb472ce5d 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -26,7 +26,7 @@ NSString * const MGLOfflinePackErrorUserInfoKey = MGLOfflinePackUserInfoKeyError
const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"MaximumCount";
NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoKeyMaximumCount;
-@interface MGLOfflineStorage () <MGLOfflinePackDelegate>
+@interface MGLOfflineStorage ()
@property (nonatomic, strong, readwrite) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *packs;
@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
@@ -40,11 +40,69 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
static MGLOfflineStorage *sharedOfflineStorage;
dispatch_once(&onceToken, ^{
sharedOfflineStorage = [[self alloc] init];
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ [[NSNotificationCenter defaultCenter] addObserver:sharedOfflineStorage selector:@selector(unpauseFileSource:) name:UIApplicationWillEnterForegroundNotification object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:sharedOfflineStorage selector:@selector(pauseFileSource:) name:UIApplicationDidEnterBackgroundNotification object:nil];
+#endif
[sharedOfflineStorage reloadPacks];
});
+
return sharedOfflineStorage;
}
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+- (void)pauseFileSource:(__unused NSNotification *)notification {
+ _mbglFileSource->pause();
+}
+
+- (void)unpauseFileSource:(__unused NSNotification *)notification {
+ _mbglFileSource->resume();
+}
+#endif
+
+- (void)setDelegate:(id<MGLOfflineStorageDelegate>)newValue {
+ _delegate = newValue;
+ if ([self.delegate respondsToSelector:@selector(offlineStorage:URLForResourceOfKind:withURL:)]) {
+ _mbglFileSource->setResourceTransform([offlineStorage = self](auto kind_, std::string&& url_) -> std::string {
+ NSURL* url =
+ [NSURL URLWithString:[[NSString alloc] initWithBytes:url_.data()
+ length:url_.length()
+ encoding:NSUTF8StringEncoding]];
+ MGLResourceKind kind = MGLResourceKindUnknown;
+ switch (kind_) {
+ case mbgl::Resource::Kind::Tile:
+ kind = MGLResourceKindTile;
+ break;
+ case mbgl::Resource::Kind::Glyphs:
+ kind = MGLResourceKindGlyphs;
+ break;
+ case mbgl::Resource::Kind::Style:
+ kind = MGLResourceKindStyle;
+ break;
+ case mbgl::Resource::Kind::Source:
+ kind = MGLResourceKindSource;
+ break;
+ case mbgl::Resource::Kind::SpriteImage:
+ kind = MGLResourceKindSpriteImage;
+ break;
+ case mbgl::Resource::Kind::SpriteJSON:
+ kind = MGLResourceKindSpriteJSON;
+ break;
+ case mbgl::Resource::Kind::Unknown:
+ kind = MGLResourceKindUnknown;
+ break;
+
+ }
+ url = [offlineStorage.delegate offlineStorage:offlineStorage
+ URLForResourceOfKind:kind
+ withURL:url];
+ return url.absoluteString.UTF8String;
+ });
+ } else {
+ _mbglFileSource->setResourceTransform(nullptr);
+ }
+}
+
/**
Returns the file URL to the offline cache, with the option to omit the private
subdirectory for legacy (v3.2.0 - v3.2.3) migration purposes.
@@ -159,13 +217,14 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
}
- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
[[MGLNetworkConfiguration sharedManager] removeObserver:self forKeyPath:@"apiBaseURL"];
[[MGLAccountManager sharedManager] removeObserver:self forKeyPath:@"accessToken"];
-
+
for (MGLOfflinePack *pack in self.packs) {
[pack invalidate];
}
-
+
delete _mbglFileSource;
_mbglFileSource = nullptr;
}
@@ -197,7 +256,6 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
pack.state = MGLOfflinePackStateInactive;
MGLOfflineStorage *strongSelf = weakSelf;
[[strongSelf mutableArrayValueForKey:@"packs"] addObject:pack];
- pack.delegate = strongSelf;
if (completion) {
completion(pack, error);
}
@@ -210,7 +268,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
@"Regions of type %@ are unsupported.", NSStringFromClass([region class])];
return;
}
-
+
const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id <MGLOfflineRegion_Private>)region offlineRegionDefinition];
mbgl::OfflineRegionMetadata metadata(context.length);
[context getBytes:&metadata[0] length:metadata.size()];
@@ -247,7 +305,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
completion(nil);
return;
}
-
+
self.mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) {
NSError *error;
if (exception) {
@@ -269,10 +327,6 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
[pack invalidate];
}
self.packs = [packs mutableCopy];
-
- for (MGLOfflinePack *pack in packs) {
- pack.delegate = self;
- }
}];
}
@@ -312,30 +366,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
if (!cachePath) {
return 0;
}
-
+
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:cachePath error:NULL];
return attributes.fileSize;
}
-#pragma mark MGLOfflinePackDelegate methods
-
-- (void)offlinePack:(MGLOfflinePack *)pack progressDidChange:(__unused MGLOfflinePackProgress)progress {
- [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackProgressChangedNotification object:pack userInfo:@{
- MGLOfflinePackUserInfoKeyState: @(pack.state),
- MGLOfflinePackUserInfoKeyProgress: [NSValue valueWithMGLOfflinePackProgress:progress],
- }];
-}
-
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveError:(NSError *)error {
- [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackErrorNotification object:pack userInfo:@{
- MGLOfflinePackUserInfoKeyError: error,
- }];
-}
-
-- (void)offlinePack:(MGLOfflinePack *)pack didReceiveMaximumAllowedMapboxTiles:(uint64_t)maximumCount {
- [[NSNotificationCenter defaultCenter] postNotificationName:MGLOfflinePackMaximumMapboxTilesReachedNotification object:pack userInfo:@{
- MGLOfflinePackUserInfoKeyMaximumCount: @(maximumCount),
- }];
-}
-
@end
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index 5d81eb85ea..da131b6de8 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -11,7 +11,7 @@
/**
Runs the preparation handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
-
+
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
@@ -23,7 +23,7 @@ void MGLPrepareCustomStyleLayer(void *context) {
/**
Runs the drawing handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
-
+
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
@@ -43,7 +43,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender
/**
Runs the completion handler block contained in the given context, which is
implicitly an instance of `MGLOpenGLStyleLayer`.
-
+
@param context An `MGLOpenGLStyleLayer` instance that was provided as context
when creating an OpenGL style layer.
*/
@@ -55,18 +55,18 @@ void MGLFinishCustomStyleLayer(void *context) {
/**
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that
you provide.
-
+
By default, this class does nothing. You can subclass this class to provide
custom OpenGL drawing code that is run on each frame of the map. Your subclass
should override the `-didMoveToMapView:`, `-willMoveFromMapView:`, and
`-drawInMapView:withContext:` methods.
-
+
You can access an existing OpenGL style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new OpenGL style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
@warning This API is undocumented and therefore unsupported. It may change at
any time without notice.
*/
@@ -76,7 +76,7 @@ void MGLFinishCustomStyleLayer(void *context) {
/**
The map view whose style currently contains the layer.
-
+
If the layer is not currently part of any map view’s style, this property is
set to `nil`.
*/
@@ -90,11 +90,11 @@ void MGLFinishCustomStyleLayer(void *context) {
/**
Returns an OpenGL style layer object initialized with the given identifier.
-
+
After initializing and configuring the style layer, add it to a map view’s
style using the `-[MGLStyle addLayer:]` or
`-[MGLStyle insertLayer:belowLayer:]` method.
-
+
@param identifier A string that uniquely identifies the layer in the style to
which it is added.
@return An initialized OpenGL style layer.
@@ -154,58 +154,58 @@ void MGLFinishCustomStyleLayer(void *context) {
/**
Called immediately after a layer is added to a map view’s style.
-
+
This method is intended to be overridden in a subclass. You can use this method
to perform any setup work before the layer is used to draw a frame. For
example, you might use this method to compile an OpenGL shader. The default
implementation of this method does nothing.
-
+
Any resource acquired in this method must be released in
`-willMoveFromMapView:`.
-
+
@param mapView The map view to whose style the layer has been added.
*/
- (void)didMoveToMapView:(MGLMapView *)mapView {
-
+
}
/**
Called immediately before a layer is removed from a map view’s style.
-
+
This method is intended to be overridden in a subclass. You can use this method
to perform any teardown work once the layer has drawn its last frame and is
about to be removed from the style. The default implementation of this method
does nothing.
-
+
This method may be called even if `-didMoveToMapView:` has not been called.
-
+
@param mapView The map view from whose style the layer is about to be removed.
*/
- (void)willMoveFromMapView:(MGLMapView *)mapView {
-
+
}
/**
Called each time the layer needs to draw a new frame in a map view.
-
+
This method is intended to be overridden in a subclass. You can use this method
to draw the layer’s content. The default implementation of this method does
nothing.
-
+
Your implementation should not make any assumptions about the OpenGL state,
other than that the current OpenGL context is active. It may make changes to
the OpenGL state. It is not required to reset values such as the depth mask,
stencil mask, or corresponding test flags to their original values.
-
+
Be sure to draw your fragments with a <var>z</var> value of 1 to take advantage
of the opaque fragment culling, in case the style contains any opaque layers
above this layer.
-
+
@param mapView The map view to which the layer draws.
@param context A context structure with information defining the frame to draw.
*/
- (void)drawInMapView:(MGLMapView *)mapView withContext:(MGLStyleLayerDrawingContext)context {
-
+
}
/**
diff --git a/platform/darwin/src/MGLOverlay.h b/platform/darwin/src/MGLOverlay.h
index cc32bad1e6..462a0c1031 100644
--- a/platform/darwin/src/MGLOverlay.h
+++ b/platform/darwin/src/MGLOverlay.h
@@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
both a point and an area on a map. Overlay objects are essentially data objects
that contain the geographic data needed to represent the map area. Overlays can
take the form of a polyline or polygon.
-
+
You use overlays to layer more sophisticated content on top of a map view. For
example, you could use an overlay to show the boundaries of a national park or
trace a bus route along city streets. This SDK defines several concrete classes
@@ -26,7 +26,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
The cooordinate rectangle that encompasses the overlay. (required) (read-only)
-
+
This property contains the smallest rectangle that completely encompasses the
overlay. Implementers of this protocol must set this area when implementing
their overlay class, and after setting it, you must not change it.
@@ -36,11 +36,11 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a Boolean indicating whether the specified rectangle intersects the
receiver’s shape.
-
+
You can implement this method to provide more specific bounds checking for an
overlay. If you do not implement it, the bounding rectangle is used to detect
intersections.
-
+
@param overlayBounds The rectangle to intersect with the receiver’s area.
@return `YES` if any part of the map rectangle intersects the receiver’s shape
or `NO` if it does not.
diff --git a/platform/darwin/src/MGLPointAnnotation.h b/platform/darwin/src/MGLPointAnnotation.h
index aeac43bd39..1ef0962f99 100644
--- a/platform/darwin/src/MGLPointAnnotation.h
+++ b/platform/darwin/src/MGLPointAnnotation.h
@@ -12,12 +12,12 @@ NS_ASSUME_NONNULL_BEGIN
`MGLPointAnnotation` object is known as a point annotation or point shape. For
example, you could use a point shape to represent a city at low zoom levels, an
address at high zoom levels, or the location of a long press gesture.
-
+
You can add point shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s point shapes collectively using an `MGLCircleStyleLayer` or
`MGLSymbolStyleLayer` object.
-
+
For more interactivity, add a selectable point annotation to a map view using
the `-[MGLMapView addAnnotation:]` method. Alternatively, define your own model
class that conforms to the `MGLAnnotation` protocol. Configure a point
@@ -26,10 +26,10 @@ NS_ASSUME_NONNULL_BEGIN
`-[MGLMapViewDelegate mapView:viewForAnnotation:]` (iOS only). A point
annotation’s `MGLShape.title` and `MGLShape.subtitle` properties define the
default content of the annotation’s callout (on iOS) or popover (on macOS).
-
+
To group multiple related points together in one shape, use an
`MGLPointCollection` or `MGLShapeCollection` object.
-
+
A point shape is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.2">Point</a> geometry
in GeoJSON.
diff --git a/platform/darwin/src/MGLPointAnnotation.mm b/platform/darwin/src/MGLPointAnnotation.mm
index a2108a9e3b..5fd3e25991 100644
--- a/platform/darwin/src/MGLPointAnnotation.mm
+++ b/platform/darwin/src/MGLPointAnnotation.mm
@@ -33,7 +33,7 @@
{
if (other == self) return YES;
if (![other isKindOfClass:[MGLPointAnnotation class]]) return NO;
-
+
MGLPointAnnotation *otherAnnotation = other;
return ([super isEqual:other]
&& self.coordinate.latitude == otherAnnotation.coordinate.latitude
diff --git a/platform/darwin/src/MGLPointCollection.h b/platform/darwin/src/MGLPointCollection.h
index c7054c6bbf..74b30385a0 100644
--- a/platform/darwin/src/MGLPointCollection.h
+++ b/platform/darwin/src/MGLPointCollection.h
@@ -11,17 +11,17 @@
points in the collection may be related but are not connected spatially. For
example, you could use a point collection to represent all the trees in an
orchard.
-
+
You can add point collections to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s point collections collectively using an
`MGLCircleStyleLayer` or `MGLSymbolStyleLayer` object.
-
+
You cannot add an `MGLPointCollection` object directly to a map view as an
annotation. However, you can create individual `MGLPointAnnotation` objects
from the `coordinates` array and add those annotation objects to the map view
using the `-[MGLMapView addAnnotations:]` method.
-
+
A point collection is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.3">MultiPoint</a>
geometry in GeoJSON. Do not confuse `MGLPointCollection` with `MGLMultiPoint`,
@@ -33,7 +33,7 @@ MGL_EXPORT
/**
Creates and returns a `MGLPointCollection` object from the specified set of
coordinates.
-
+
@param coords The array of coordinates defining the shape. The data in this
array is copied to the new object.
@param count The number of items in the `coords` array.
@@ -49,7 +49,7 @@ MGL_EXPORT
/**
Retrieves one or more coordinates associated with the shape.
-
+
@param coords On input, you must provide a C array of structures large enough
to hold the desired number of coordinates. On output, this structure
contains the requested coordinate data.
diff --git a/platform/darwin/src/MGLPointCollection.mm b/platform/darwin/src/MGLPointCollection.mm
index acd78b8b33..ac4aaed60c 100644
--- a/platform/darwin/src/MGLPointCollection.mm
+++ b/platform/darwin/src/MGLPointCollection.mm
@@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLPointCollection class]]) return NO;
-
+
MGLPointCollection *otherCollection = (MGLPointCollection *)other;
return ([super isEqual:other]
&& ((![self geoJSONDictionary] && ![otherCollection geoJSONDictionary]) || [[self geoJSONDictionary] isEqualToDictionary:[otherCollection geoJSONDictionary]]));
@@ -112,7 +112,7 @@ NS_ASSUME_NONNULL_BEGIN
CLLocationCoordinate2D coordinate = self.coordinates[index];
[coordinates addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
}
-
+
return @{@"type": @"MultiPoint",
@"coordinates": coordinates};
}
diff --git a/platform/darwin/src/MGLPolygon+MGLAdditions.m b/platform/darwin/src/MGLPolygon+MGLAdditions.m
index def4687016..3e76a37157 100644
--- a/platform/darwin/src/MGLPolygon+MGLAdditions.m
+++ b/platform/darwin/src/MGLPolygon+MGLAdditions.m
@@ -4,14 +4,14 @@
- (NS_ARRAY_OF(id) *)mgl_coordinates {
NSMutableArray *coordinates = [NSMutableArray array];
-
+
NSMutableArray *exteriorRing = [NSMutableArray array];
for (NSUInteger index = 0; index < self.pointCount; index++) {
CLLocationCoordinate2D coordinate = self.coordinates[index];
[exteriorRing addObject:@[@(coordinate.longitude), @(coordinate.latitude)]];
}
[coordinates addObject:exteriorRing];
-
+
for (MGLPolygon *interiorPolygon in self.interiorPolygons) {
NSMutableArray *interiorRing = [NSMutableArray array];
for (int index = 0; index < interiorPolygon.pointCount; index++) {
@@ -20,7 +20,7 @@
}
[coordinates addObject:interiorRing];
}
-
+
return [coordinates copy];
}
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 560741a150..3fcc1be76d 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -14,25 +14,25 @@ NS_ASSUME_NONNULL_BEGIN
vertices, specified as `CLLocationCoordinate2D` instances, and the edges that
connect them. For example, you could use a polygon shape to represent a
building, a lake, or an area you want to highlight.
-
+
You can add polygon shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s polygons collectively using an `MGLFillStyleLayer` or
`MGLSymbolStyleLayer` object.
-
+
Alternatively, you can add a polygon overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
a polygon overlay’s appearance using
`-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
`-[MGLMapViewDelegate mapView:fillColorForPolygonAnnotation:]`.
-
+
The vertices are automatically connected in the order in which you provide
them. You should close the polygon by specifying the same
`CLLocationCoordinate2D` as the first and last vertices; otherwise, the
polygon’s fill may not cover the area you expect it to. To avoid filling the
space within the shape, give the polygon a transparent fill or use an
`MGLPolyline` object.
-
+
A polygon may have one or more interior polygons, or holes, that you specify as
`MGLPolygon` objects with the `+polygonWithCoordinates:count:interiorPolygons:`
method. For example, if a polygon represents a lake, it could exclude an island
@@ -40,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
have interior polygons. To represent a shape that includes a polygon within a
hole or, more generally, to group multiple polygons together in one shape, use
an `MGLMultiPolygon` or `MGLShapeCollection` object.
-
+
To make the polygon straddle the antimeridian, specify some longitudes less
than −180 degrees or greater than 180 degrees.
*/
@@ -49,11 +49,11 @@ MGL_EXPORT
/**
The array of polygons nested inside the receiver.
-
+
The area occupied by any interior polygons is excluded from the overall shape.
Interior polygons should not overlap. An interior polygon should not have
interior polygons of its own.
-
+
If there are no interior polygons, the value of this property is `nil`.
*/
@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons;
@@ -61,7 +61,7 @@ MGL_EXPORT
/**
Creates and returns an `MGLPolygon` object from the specified set of
coordinates.
-
+
@param coords The array of coordinates defining the shape. The data in this
array is copied to the new object.
@param count The number of items in the `coords` array.
@@ -72,7 +72,7 @@ MGL_EXPORT
/**
Creates and returns an `MGLPolygon` object from the specified set of
coordinates and interior polygons.
-
+
@param coords The array of coordinates defining the shape. The data in this
array is copied to the new object.
@param count The number of items in the `coords` array.
@@ -92,12 +92,12 @@ MGL_EXPORT
atoll: the inner island would be one `MGLPolygon` object, while the surrounding
atoll would be another. You could also use a multipolygon shape to represent a
group of disconnected but related buildings.
-
+
You can add multipolygon shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s multipolygons collectively using an `MGLFillStyleLayer` or
`MGLSymbolStyleLayer` object.
-
+
You cannot add an `MGLMultiPolygon` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
add the `polygons` array’s items as overlays individually.
@@ -112,7 +112,7 @@ MGL_EXPORT
/**
Creates and returns a multipolygon object consisting of the given polygons.
-
+
@param polygons The array of polygons defining the shape.
@return A new multipolygon object.
*/
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 565de017cc..ceafe873bf 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -44,7 +44,7 @@
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLPolygon class]]) return NO;
-
+
MGLPolygon *otherPolygon = (MGLPolygon *)other;
return ([super isEqual:otherPolygon] &&
[[self geoJSONDictionary] isEqualToDictionary:[otherPolygon geoJSONDictionary]]);
@@ -80,7 +80,7 @@
}
- (mbgl::Annotation)annotationObjectWithDelegate:(id <MGLMultiPointDelegate>)delegate {
-
+
mbgl::FillAnnotation annotation { [self polygon] };
annotation.opacity = { static_cast<float>([delegate alphaForShapeAnnotation:self]) };
annotation.outlineColor = { [delegate strokeColorForShapeAnnotation:self] };
@@ -115,9 +115,9 @@
- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
if (self = [super init]) {
_polygons = polygons;
-
+
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
-
+
for (MGLPolygon *polygon in _polygons) {
bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polygon.overlayBounds));
}
@@ -141,7 +141,7 @@
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPolygon class]]) return NO;
-
+
MGLMultiPolygon *otherMultiPolygon = other;
return [super isEqual:other]
&& [self.polygons isEqualToArray:otherMultiPolygon.polygons];
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index ca1f8e36cc..b3db0fd39f 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -14,28 +14,28 @@ NS_ASSUME_NONNULL_BEGIN
specified as `CLLocationCoordinate2D` instances, and the line segments that
connect them. For example, you could use an polyline to represent a road or the
path along which something moves.
-
+
You can add polyline shapes to the map by adding them to an `MGLShapeSource`
object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s polylines collectively using an `MGLLineStyleLayer` or
`MGLSymbolStyleLayer` object.
-
+
Alternatively, you can add a polyline overlay directly to a map view using the
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]` method. Configure
a polyline overlay’s appearance using
`-[MGLMapViewDelegate mapView:strokeColorForShapeAnnotation:]` and
`-[MGLMapViewDelegate mapView:lineWidthForPolylineAnnotation:]`.
-
+
The vertices are automatically connected in the order in which you provide
them. The first and last vertices are not connected to each other, but you can
specify the same `CLLocationCoordinate2D` as the first and last vertices in
order to close the polyline. To fill the space within the shape, use an
`MGLPolygon` object. To group multiple polylines together in one shape, use an
`MGLMultiPolyline` or `MGLShapeCollection` object.
-
+
To make the polyline straddle the antimeridian, specify some longitudes less
than −180 degrees or greater than 180 degrees.
-
+
A polyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.4">LineString</a>
geometry in GeoJSON.
@@ -46,7 +46,7 @@ MGL_EXPORT
/**
Creates and returns an `MGLPolyline` object from the specified set of
coordinates.
-
+
@param coords The array of coordinates defining the shape. The data in this
array is copied to the new object.
@param count The number of items in the `coords` array.
@@ -61,16 +61,16 @@ MGL_EXPORT
polylines. For example, you could use a multipolyline shape to represent both
sides of a divided highway (dual carriageway), excluding the median (central
reservation): each carriageway would be a distinct `MGLPolyline` object.
-
+
You can add multipolyline shapes to the map by adding them to an
`MGLShapeSource` object. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s multipolylines collectively using an `MGLLineStyleLayer` or
`MGLSymbolStyleLayer` object.
-
+
You cannot add an `MGLMultiPolyline` object directly to a map view using
`-[MGLMapView addAnnotation:]` or `-[MGLMapView addOverlay:]`. However, you can
add the `polylines` array’s items as overlays individually.
-
+
A multipolyline is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.5">MultiLineString</a>
geometry in GeoJSON.
@@ -85,7 +85,7 @@ MGL_EXPORT
/**
Creates and returns a multipolyline object consisting of the given polylines.
-
+
@param polylines The array of polylines defining the shape.
@return A new multipolyline object.
*/
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index e6b1cdebf6..454a1b964b 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -20,13 +20,13 @@
- (mbgl::LineString<double>)lineString {
NSUInteger count = self.pointCount;
CLLocationCoordinate2D *coordinates = self.coordinates;
-
+
mbgl::LineString<double> geometry;
geometry.reserve(self.pointCount);
for (NSUInteger i = 0; i < count; i++) {
geometry.push_back(mbgl::Point<double>(coordinates[i].longitude, coordinates[i].latitude));
}
-
+
return geometry;
}
@@ -69,9 +69,9 @@
- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
if (self = [super init]) {
_polylines = polylines;
-
+
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
-
+
for (MGLPolyline *polyline in _polylines) {
bounds.extend(MGLLatLngBoundsFromCoordinateBounds(polyline.overlayBounds));
}
@@ -96,7 +96,7 @@
{
if (self == other) return YES;
if (![other isKindOfClass:[MGLMultiPolyline class]]) return NO;
-
+
MGLMultiPolyline *otherMultipoline = other;
return ([super isEqual:otherMultipoline]
&& [self.polylines isEqualToArray:otherMultipoline.polylines]);
@@ -127,7 +127,7 @@
NSMutableArray *coordinates = [NSMutableArray array];
for (MGLPolylineFeature *feature in self.polylines) {
[coordinates addObject: feature.mgl_coordinates];
- }
+ }
return @{@"type": @"MultiLineString",
@"coordinates": coordinates};
}
diff --git a/platform/darwin/src/MGLRasterSource.h b/platform/darwin/src/MGLRasterSource.h
index ac5be60105..694a818246 100644
--- a/platform/darwin/src/MGLRasterSource.h
+++ b/platform/darwin/src/MGLRasterSource.h
@@ -10,12 +10,12 @@ NS_ASSUME_NONNULL_BEGIN
width and height (measured in points) at which the map displays each raster
image tile when the map’s zoom level is an integer. The raster source scales
its images up or down when the map’s zoom level falls between two integers.
-
+
The default value for this option is 512. Version 4 of the
<a href="https://www.mapbox.com/api-documentation/#maps">Mapbox Maps API</a>
requires a value of 256, as do many third-party tile servers, so consult your
provider’s documentation for the correct value.
-
+
This option is only applicable to `MGLRasterSource` objects; it is ignored when
initializing `MGLVectorSource` objects.
*/
@@ -29,16 +29,16 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileSize;
A raster source is added to an `MGLStyle` object along with one or more
`MGLRasterStyleLayer` objects. Use a raster style layer to control the
appearance of content supplied by the raster source.
-
+
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-raster"><code>raster</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLRasterSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
-
+
### Example
-
+
```swift
let source = MGLRasterSource(identifier: "clouds", tileURLTemplates: ["https://example.com/raster-tiles/{z}/{x}/{y}.png"], options: [
.minimumZoomLevel: 9,
@@ -58,21 +58,21 @@ MGL_EXPORT
/**
Returns a raster source initialized with an identifier and configuration URL.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
-
+
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
-
+
If a Mapbox URL is specified, this source uses a tile size of 256. For all
other tile sets, the default value is 512. (See the
`MGLTileSourceOptionTileSize` documentation for more information about tile
sizes.) If you need to use a tile size other than the default, use the
`-initWithIdentifier:configurationURL:tileSize:` method.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
@@ -84,15 +84,15 @@ MGL_EXPORT
/**
Returns a raster source initialized with an identifier, configuration URL, and
tile size.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
-
+
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
diff --git a/platform/darwin/src/MGLRasterSource.mm b/platform/darwin/src/MGLRasterSource.mm
index fd36413fe0..c73a824ea8 100644
--- a/platform/darwin/src/MGLRasterSource.mm
+++ b/platform/darwin/src/MGLRasterSource.mm
@@ -50,7 +50,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
-
+
uint16_t tileSize = MGLRasterSourceRetinaTileSize;
if (NSNumber *tileSizeNumber = options[MGLTileSourceOptionTileSize]) {
if (![tileSizeNumber isKindOfClass:[NSNumber class]]) {
@@ -59,7 +59,7 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
}
tileSize = static_cast<uint16_t>(round(tileSizeNumber.doubleValue));
}
-
+
auto source = std::make_unique<mbgl::style::RasterSource>(identifier.UTF8String, tileSet, tileSize);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
@@ -82,9 +82,20 @@ static const CGFloat MGLRasterSourceRetinaTileSize = 512;
}
- (void)removeFromMapView:(MGLMapView *)mapView {
+ if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
+ return;
+ }
+
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
- _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::RasterSource> &>(removedSource));
+ mbgl::style::RasterSource *source = dynamic_cast<mbgl::style::RasterSource *>(removedSource.get());
+ if (!source) {
+ return;
+ }
+
+ removedSource.release();
+
+ _pendingSource = std::unique_ptr<mbgl::style::RasterSource>(source);
self.rawSource = _pendingSource.get();
}
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index cd57a74f6a..9e876a6e3c 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -18,15 +18,15 @@ NS_ASSUME_NONNULL_BEGIN
set</a> uploaded to Mapbox Studio, or a raster map authored in <a
href="https://tilemill-project.github.io/tilemill/">TileMill</a>, the classic
Mapbox Editor, or Mapbox Studio Classic.
-
+
You can access an existing raster style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new raster style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
@@ -49,6 +49,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-max"><code>raster-brightness-max</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumRasterBrightness;
@@ -65,6 +72,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-brightness-min"><code>raster-brightness-min</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *minimumRasterBrightness;
@@ -76,6 +90,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterContrast;
@@ -87,6 +108,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `300`. Set this property to `nil` to
reset it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterFadeDuration;
@@ -102,6 +130,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-raster-hue-rotate"><code>raster-hue-rotate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterHueRotation;
@@ -113,6 +148,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterOpacity;
@@ -122,6 +164,13 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `0`. Set this property to `nil` to reset
it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *rasterSaturation;
diff --git a/platform/darwin/src/MGLRasterStyleLayer.mm b/platform/darwin/src/MGLRasterStyleLayer.mm
index 87afb8da9d..2108a5a0c8 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.mm
+++ b/platform/darwin/src/MGLRasterStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -45,7 +45,7 @@
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -69,8 +69,9 @@
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -93,14 +94,17 @@
- (void)setMaximumRasterBrightness:(MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumRasterBrightness);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumRasterBrightness);
self.rawLayer->setRasterBrightnessMax(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)maximumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterBrightnessMax() ?: self.rawLayer->getDefaultRasterBrightnessMax();
+ auto propertyValue = self.rawLayer->getRasterBrightnessMax();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMax());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -114,14 +118,17 @@
- (void)setMinimumRasterBrightness:(MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(minimumRasterBrightness);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(minimumRasterBrightness);
self.rawLayer->setRasterBrightnessMin(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)minimumRasterBrightness {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterBrightnessMin() ?: self.rawLayer->getDefaultRasterBrightnessMin();
+ auto propertyValue = self.rawLayer->getRasterBrightnessMin();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterBrightnessMin());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -135,42 +142,51 @@
- (void)setRasterContrast:(MGLStyleValue<NSNumber *> *)rasterContrast {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterContrast);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterContrast);
self.rawLayer->setRasterContrast(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterContrast {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterContrast() ?: self.rawLayer->getDefaultRasterContrast();
+ auto propertyValue = self.rawLayer->getRasterContrast();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterContrast());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterFadeDuration:(MGLStyleValue<NSNumber *> *)rasterFadeDuration {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterFadeDuration);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterFadeDuration);
self.rawLayer->setRasterFadeDuration(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterFadeDuration {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterFadeDuration() ?: self.rawLayer->getDefaultRasterFadeDuration();
+ auto propertyValue = self.rawLayer->getRasterFadeDuration();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterFadeDuration());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterHueRotation:(MGLStyleValue<NSNumber *> *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterHueRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterHueRotation);
self.rawLayer->setRasterHueRotate(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterHueRotation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterHueRotate() ?: self.rawLayer->getDefaultRasterHueRotate();
+ auto propertyValue = self.rawLayer->getRasterHueRotate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterHueRotate());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -184,28 +200,34 @@
- (void)setRasterOpacity:(MGLStyleValue<NSNumber *> *)rasterOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterOpacity);
self.rawLayer->setRasterOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterOpacity() ?: self.rawLayer->getDefaultRasterOpacity();
+ auto propertyValue = self.rawLayer->getRasterOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterOpacity());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setRasterSaturation:(MGLStyleValue<NSNumber *> *)rasterSaturation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(rasterSaturation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(rasterSaturation);
self.rawLayer->setRasterSaturation(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)rasterSaturation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getRasterSaturation() ?: self.rawLayer->getDefaultRasterSaturation();
+ auto propertyValue = self.rawLayer->getRasterSaturation();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultRasterSaturation());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLShape.h b/platform/darwin/src/MGLShape.h
index d1c150d02e..bd8b6152d2 100644
--- a/platform/darwin/src/MGLShape.h
+++ b/platform/darwin/src/MGLShape.h
@@ -9,19 +9,19 @@ NS_ASSUME_NONNULL_BEGIN
`MGLShape` is an abstract class that represents a shape or annotation. Shapes
constitute the content of a map – not only the overlays atop the map, but also
the content that forms the base map.
-
+
You do not create instances of this class directly or create subclasses of this
- class. Instead, you create instances of `MGLPointAnnotation`,
+ class. Instead, you create instances of `MGLPointAnnotation`,
`MGLPointCollection`, `MGLPolyline`, `MGLMultiPolyline`, `MGLPolygon`,
`MGLMultiPolygon`, or `MGLShapeCollection`. The shape classes correspond to the
<a href="https://tools.ietf.org/html/rfc7946#section-3.1">Geometry</a> object
types in the GeoJSON standard, but some have nonstandard names for backwards
compatibility.
-
+
Although you do not create instances of this class directly, you can use its
`+[MGLShape shapeWithData:encoding:error:]` factory method to create one of the
concrete subclasses of `MGLShape` noted above from GeoJSON data.
-
+
You can add shapes to the map by adding them to an `MGLShapeSource` object.
Configure the appearance of an `MGLShapeSource`’s or `MGLVectorSource`’s shapes
collectively using a concrete instance of `MGLVectorStyleLayer`. Alternatively,
@@ -36,21 +36,21 @@ MGL_EXPORT
/**
Returns an `MGLShape` object initialized with the given data interpreted as a
string containing a GeoJSON object.
-
+
If the GeoJSON object is a geometry, the returned value is a kind of
`MGLShape`. If it is a feature object, the returned value is a kind of
`MGLShape` that conforms to the `MGLFeature` protocol. If it is a feature
collection object, the returned value is an instance of
`MGLShapeCollectionFeature`.
-
+
### Example
-
+
```swift
let url = mainBundle.url(forResource: "amsterdam", withExtension: "geojson")!
let data = try! Data(contentsOf: url)
let feature = try! MGLShape(data: data, encoding: String.Encoding.utf8.rawValue) as! MGLShapeCollectionFeature
```
-
+
@param data String data containing GeoJSON source code.
@param encoding The encoding used by `data`.
@param outError Upon return, if an error has occurred, a pointer to an
@@ -65,9 +65,9 @@ MGL_EXPORT
/**
The title of the shape annotation.
-
+
The default value of this property is `nil`.
-
+
This property is ignored when the shape is used in an `MGLShapeSource`. To name
a shape used in a shape source, create an `MGLFeature` and add an attribute to
the `MGLFeature.attributes` property.
@@ -77,7 +77,7 @@ MGL_EXPORT
/**
The subtitle of the shape annotation. The default value of this property is
`nil`.
-
+
This property is ignored when the shape is used in an `MGLShapeSource`. To
provide additional information about a shape used in a shape source, create an
`MGLFeature` and add an attribute to the `MGLFeature.attributes` property.
@@ -88,9 +88,9 @@ MGL_EXPORT
/**
The tooltip of the shape annotation.
-
+
The default value of this property is `nil`.
-
+
This property is ignored when the shape is used in an `MGLShapeSource`.
*/
@property (nonatomic, copy, nullable) NSString *toolTip;
@@ -102,7 +102,7 @@ MGL_EXPORT
/**
Returns the GeoJSON string representation of the shape encapsulated in a data
object.
-
+
@param encoding The string encoding to use.
@return A data object containing the shape’s GeoJSON string representation.
*/
diff --git a/platform/darwin/src/MGLShape.mm b/platform/darwin/src/MGLShape.mm
index 984235fd97..e76e06c7e4 100644
--- a/platform/darwin/src/MGLShape.mm
+++ b/platform/darwin/src/MGLShape.mm
@@ -21,7 +21,7 @@ bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D r
}
return nil;
}
-
+
try {
const auto geojson = mapbox::geojson::parse(string.UTF8String);
return MGLShapeFromGeoJSON(geojson);
@@ -81,7 +81,7 @@ bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D r
{
if (other == self) { return YES; }
id <MGLAnnotation> annotation = other;
-
+
#if TARGET_OS_IPHONE
return ((!_title && ![annotation title]) || [_title isEqualToString:[annotation title]])
&& ((!_subtitle && ![annotation subtitle]) || [_subtitle isEqualToString:[annotation subtitle]]);
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
index 5d2ce588c9..bb107ee7f0 100644
--- a/platform/darwin/src/MGLShapeCollection.h
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -11,25 +11,25 @@ NS_ASSUME_NONNULL_BEGIN
An `MGLShapeCollection` object represents a shape consisting of zero or more
distinct but related shapes that are instances of `MGLShape`. The constituent
shapes can be a mixture of different kinds of shapes.
-
+
`MGLShapeCollection` is most commonly used to add multiple shapes to a single
`MGLShapeSource`. Configure the appearance of an `MGLShapeSource`’s or
`MGLVectorSource`’s shape collection collectively using an
`MGLSymbolStyleLayer` object, or use multiple instances of
`MGLCircleStyleLayer`, `MGLFillStyleLayer`, and `MGLLineStyleLayer` to
configure the appearance of each kind of shape inside the collection.
-
+
You cannot add an `MGLShapeCollection` object directly to a map view as an
annotation. However, you can create individual `MGLPointAnnotation`,
`MGLPolyline`, and `MGLPolygon` objects from the `shapes` array and add those
annotation objects to the map view using the `-[MGLMapView addAnnotations:]`
method.
-
+
To represent a collection of point, polyline, or polygon shapes, it may be more
convenient to use an `MGLPointCollection`, `MGLMultiPolyline`, or
`MGLMultiPolygon` object, respectively.
-
- A multipolyline is known as a
+
+ A shape collection is known as a
<a href="https://tools.ietf.org/html/rfc7946#section-3.1.8">GeometryCollection</a>
geometry in GeoJSON.
*/
@@ -43,7 +43,7 @@ MGL_EXPORT
/**
Creates and returns a shape collection consisting of the given shapes.
-
+
@param shapes The array of shapes defining the shape collection. The data in
this array is copied to the new object.
@return A new shape collection object.
diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm
index 4b468a1cbb..03cab0043f 100644
--- a/platform/darwin/src/MGLShapeCollection.mm
+++ b/platform/darwin/src/MGLShapeCollection.mm
@@ -32,7 +32,7 @@
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLShapeCollection class]]) return NO;
-
+
MGLShapeCollection *otherShapeCollection = other;
return [super isEqual:otherShapeCollection]
&& [_shapes isEqualToArray:otherShapeCollection.shapes];
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 66056f7424..ed11dc0ce1 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -9,13 +9,84 @@ NS_ASSUME_NONNULL_BEGIN
@protocol MGLFeature;
/**
+ Options for `MGLShapeSource` objects.
+ */
+typedef NSString *MGLShapeSourceOption NS_STRING_ENUM;
+
+/**
+ An `NSNumber` object containing a Boolean enabling or disabling clustering.
+ If the `shape` property contains point shapes, setting this option to
+ `YES` clusters the points by radius into groups. The default value is `NO`.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-cluster"><code>cluster</code></a>
+ source property in the Mapbox Style Specification.
+
+ This option only affects point features within a shape source.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClustered;
+
+/**
+ An `NSNumber` object containing an integer; specifies the radius of each
+ cluster if clustering is enabled. A value of 512 produces a radius equal to
+ the width of a tile. The default value is 50.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius;
+
+/**
+ An `NSNumber` object containing an integer; specifies the maximum zoom level at
+ which to cluster points if clustering is enabled. Defaults to one zoom level
+ less than the value of `MGLShapeSourceOptionMaximumZoomLevel` so that, at the
+ maximum zoom level, the shapes are not clustered.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-clusterMaxZoom"><code>clusterMaxZoom</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering;
+
+/**
+ An `NSNumber` object containing an integer; specifies the maximum zoom level at
+ which to create vector tiles. A greater value produces greater detail at high
+ zoom levels. The default value is 18.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-maxzoom"><code>maxzoom</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel;
+
+/**
+ An `NSNumber` object containing an integer; specifies the size of the tile
+ buffer on each side. A value of 0 produces no buffer. A value of 512 produces a
+ buffer as wide as the tile itself. Larger values produce fewer rendering
+ artifacts near tile edges and slower performance. The default value is 128.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-buffer"><code>buffer</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuffer;
+
+/**
+ An `NSNumber` object containing a double; specifies the Douglas-Peucker
+ simplification tolerance. A greater value produces simpler geometries and
+ improves performance. The default value is 0.375.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson-tolerance"><code>tolerance</code></a>
+ source property in the Mapbox Style Specification.
+ */
+extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance;
+
+/**
`MGLShapeSource` is a map content source that supplies vector shapes to be
shown on the map. The shapes may be instances of `MGLShape` or `MGLFeature`,
or they may be defined by local or external
<a href="http://geojson.org/">GeoJSON</a> code. A shape source is added to an
`MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
layer defines the appearance of any content supplied by the shape source.
-
+
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson"><code>geojson</code></a>
source defined by the style JSON file is represented at runtime by an
@@ -23,12 +94,12 @@ NS_ASSUME_NONNULL_BEGIN
initialize new style layers. You can also add and remove sources dynamically
using methods such as `-[MGLStyle addSource:]` and
`-[MGLStyle sourceWithIdentifier:]`.
-
+
Any vector style layer initialized with a shape source should have a `nil`
value in its `sourceLayerIdentifier` property.
-
+
### Example
-
+
```swift
var coordinates: [CLLocationCoordinate2D] = [
CLLocationCoordinate2D(latitude: 37.77, longitude: -122.42),
@@ -47,9 +118,9 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, URL, and dictionary of options for
the source.
-
+
@param identifier A string that uniquely identifies the source.
- @param URL An HTTP(S) URL, absolute file URL, or local file URL relative to the
+ @param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
current application’s resource bundle.
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
@@ -59,17 +130,17 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, a shape, and dictionary of options
for the source.
-
+
To specify attributes about the shape, use an instance of an `MGLShape`
subclass that conforms to the `MGLFeature` protocol, such as `MGLPointFeature`.
To include multiple shapes in the source, use an `MGLShapeCollection` or
`MGLShapeCollectionFeature` object, or use the
- `-initWithIdentifier:features:options:` or
+ `-initWithIdentifier:features:options:` or
`-initWithIdentifier:shapes:options:` methods.
-
+
To create a shape from GeoJSON source code, use the
`+[MGLShape shapeWithData:encoding:error:]` method.
-
+
@param identifier A string that uniquely identifies the source.
@param shape A concrete subclass of `MGLShape`
@param options An `NSDictionary` of options for this source.
@@ -80,7 +151,7 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, an array of features, and a dictionary
of options for the source.
-
+
Unlike `-initWithIdentifier:shapes:options:`, this method accepts `MGLFeature`
instances, such as `MGLPointFeature` objects, whose attributes you can use when
applying a predicate to `MGLVectorStyleLayer` or configuring a style layer’s
@@ -99,11 +170,11 @@ MGL_EXPORT
/**
Returns a shape source with an identifier, an array of shapes, and a dictionary of
options for the source.
-
+
Any `MGLFeature` instance passed into this initializer is treated as an ordinary
shape, causing any attributes to be inaccessible to an `MGLVectorStyleLayer` when
- evaluating a predicate or configuring certain layout or paint attributes. To
- preserve the attributes associated with each feature, use the
+ evaluating a predicate or configuring certain layout or paint attributes. To
+ preserve the attributes associated with each feature, use the
`-initWithIdentifier:features:options:` method instead.
To create a shape from GeoJSON source code, use the
@@ -125,8 +196,8 @@ MGL_EXPORT
If the receiver was initialized using `-initWithIdentifier:URL:options:`, this
property is set to `nil`. This property is unavailable until the receiver is
passed into `-[MGLStyle addSource:]`.
-
- You can get/set the shapes within a collection via this property. Actions must
+
+ You can get/set the shapes within a collection via this property. Actions must
be performed on the application's main thread.
*/
@property (nonatomic, copy, nullable) MGLShape *shape;
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 7a9e8b1646..67b6dc5a47 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -11,7 +11,12 @@
#include <mbgl/map/map.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
-
+const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered";
+const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius";
+const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering";
+const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel";
+const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer";
+const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
@interface MGLShapeSource ()
@@ -30,10 +35,10 @@
if (self = [super initWithIdentifier:identifier]) {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
-
+
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
-
+
self.URL = url;
}
return self;
@@ -43,10 +48,10 @@
if (self = [super initWithIdentifier:identifier]) {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
-
+
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
-
+
self.shape = shape;
}
return self;
@@ -82,9 +87,20 @@
}
- (void)removeFromMapView:(MGLMapView *)mapView {
+ if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
+ return;
+ }
+
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
- _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::GeoJSONSource> &>(removedSource));
+ mbgl::style::GeoJSONSource *source = dynamic_cast<mbgl::style::GeoJSONSource *>(removedSource.get());
+ if (!source) {
+ return;
+ }
+
+ removedSource.release();
+
+ _pendingSource = std::unique_ptr<mbgl::style::GeoJSONSource>(source);
self.rawSource = _pendingSource.get();
}
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index 7b3242e3ae..8bf48907cc 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -10,12 +10,12 @@ NS_ASSUME_NONNULL_BEGIN
`MGLStyle` object along with an `MGLForegroundStyleLayer` object. The
foreground style layer defines the appearance of any content supplied by the
source.
-
+
Each source defined by the style JSON file is represented at runtime by an
`MGLSource` object that you can use to refine the map’s content. You can also
add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
-
+
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLShapeSource` and the
concrete subclasses of `MGLTileSource`, `MGLVectorSource` and `MGLRasterSource`.
@@ -29,10 +29,10 @@ MGL_EXPORT
/**
Returns a source initialized with an identifier.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@return An initialized source.
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index 6e1d2e379c..acb325e2f3 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -18,29 +18,29 @@ namespace mbgl {
- (instancetype)initWithRawSource:(mbgl::style::Source *)rawSource;
/**
- A raw pointer to the mbgl object, which is always initialized, either to the
+ A raw pointer to the mbgl object, which is always initialized, either to the
value returned by `mbgl::Map getSource`, or for independently created objects,
to the pointer value held in `pendingSource`. In the latter case, this raw
- pointer value stays even after ownership of the object is transferred via
+ pointer value stays even after ownership of the object is transferred via
`mbgl::Map addSource`.
*/
@property (nonatomic) mbgl::style::Source *rawSource;
/**
Adds the mbgl source that this object represents to the mbgl map.
-
+
Once a mbgl source is added, ownership of the object is transferred to the
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
- `mbgl::Source`. If this object's mbgl source is in that state, the mbgl source
- can still be changed but the changes will not be visible until the `MGLSource`
- is added back to the map via `-[MGLStyle addSource:]` and styled with a
+ `mbgl::Source`. If this object's mbgl source is in that state, the mbgl source
+ can still be changed but the changes will not be visible until the `MGLSource`
+ is added back to the map via `-[MGLStyle addSource:]` and styled with a
`MGLLayer`.
*/
- (void)addToMapView:(MGLMapView *)mapView;
/**
Removes the mbgl source that this object represents from the mbgl map.
-
+
When a mbgl source is removed, ownership of the object is transferred back
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
safe to add the source back to the style after it is removed.
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 25096748f6..689faf78cf 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -32,16 +32,16 @@ static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 9;
/**
The proxy object for the current map style.
-
+
MGLStyle provides a set of convenience methods for changing Mapbox
default styles using `-[MGLMapView styleURL]`.
<a href="https://www.mapbox.com/maps/">Learn more about Mapbox default styles</a>.
-
- It is also possible to directly manipulate the current map style
+
+ It is also possible to directly manipulate the current map style
via `-[MGLMapView style]` by updating the style's data sources or layers.
-
+
@note Wait until the map style has finished loading before modifying a map's
- style via any of the `MGLStyle` instance methods below. You can use the
+ style via any of the `MGLStyle` instance methods below. You can use the
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` methods as indicators
that it's safe to modify the map's style.
@@ -199,7 +199,7 @@ MGL_EXPORT
@note Source identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids source identifer name changes that will occur in the default
style’s sources over time.
@@ -211,15 +211,15 @@ MGL_EXPORT
/**
Adds a new source to the current style.
-
+
@note Adding the same source instance more than once will result in a
`MGLRedundantSourceException`. Reusing the same source identifier, even with
- different source instances, will result in a
- `MGLRedundantSourceIdentifierException`.
-
- @note Sources should be added in
+ different source instances, will result in a
+ `MGLRedundantSourceIdentifierException`.
+
+ @note Sources should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new source.
@param source The source to add to the current style.
@@ -228,11 +228,11 @@ MGL_EXPORT
/**
Removes a source from the current style.
-
+
@note Source identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids source identifer name changes that will occur in the default
style’s sources over time.
@@ -251,15 +251,15 @@ MGL_EXPORT
/**
Returns a style layer with the given identifier in the current style.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set
the style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
-
+
@return An instance of a concrete subclass of `MGLStyleLayer` associated with
the given identifier, or `nil` if the current style contains no such style
layer.
@@ -268,14 +268,14 @@ MGL_EXPORT
/**
Adds a new layer on top of existing layers.
-
+
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
- different layer instances, will also result in an exception.
-
- @note Layers should be added in
+ different layer instances, will also result in an exception.
+
+ @note Layers should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new layer.
@param layer The layer object to add to the map view. This object must be an
@@ -285,14 +285,14 @@ MGL_EXPORT
/**
Inserts a new layer into the style at the given index.
-
+
@note Adding the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
- different layer instances, will also result in an exception.
-
+ different layer instances, will also result in an exception.
+
@note Layers should be added in
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
+ `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` to ensure that the map
has loaded the style and is ready to accept a new layer.
@param layer The layer to insert.
@@ -304,15 +304,15 @@ MGL_EXPORT
/**
Inserts a new layer below another layer.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set
the style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
-
+
Inserting the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
different layer instances, will also result in an exception.
@@ -324,15 +324,15 @@ MGL_EXPORT
/**
Inserts a new layer above another layer.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set
the style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
-
+
Inserting the same layer instance more than once will result in a
`MGLRedundantLayerException`. Reusing the same layer identifer, even with
different layer instances, will also result in an exception.
@@ -344,11 +344,11 @@ MGL_EXPORT
/**
Removes a layer from the map view.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set
the style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
@@ -363,7 +363,7 @@ MGL_EXPORT
/**
Currently active style classes, represented as an array of string identifiers.
*/
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses;
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property will be removed in a future release.")));
/**
Returns a Boolean value indicating whether the style class with the given
@@ -372,43 +372,43 @@ MGL_EXPORT
@param styleClass The style class to query for.
@return Whether the style class is currently active.
*/
-- (BOOL)hasStyleClass:(NSString *)styleClass;
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
/**
Activates the style class with the given identifier.
@param styleClass The style class to activate.
*/
-- (void)addStyleClass:(NSString *)styleClass;
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
/**
Deactivates the style class with the given identifier.
-
+
@note Style class names are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids style class name changes that will occur in the default
style over time.
@param styleClass The style class to deactivate.
*/
-- (void)removeStyleClass:(NSString *)styleClass;
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
#pragma mark Managing a Style’s Images
/**
Returns the image associated with the given name in the style.
-
+
@note Names and their associated images are not guaranteed to exist across
styles or different versions of the same style. Applications that use this
API must first set the style URL to an explicitly versioned style using a
convenience method like `+[MGLStyle outdoorsStyleURLWithVersion:]`,
- `MGLMapView`'s “Style URL” inspectable in Interface Builder, or a manually
- constructed `NSURL`. This approach also avoids image name changes that will
+ `MGLMapView`’s “Style URL” inspectable in Interface Builder, or a manually
+ constructed `NSURL`. This approach also avoids image name changes that will
occur in the default style over time.
-
+
@param name The name associated with the image you want to obtain.
@return The image associated with the given name, or `nil` if no image is
associated with that name.
@@ -417,11 +417,11 @@ MGL_EXPORT
/**
Adds or overrides an image used by the style’s layers.
-
+
To use an image in a style layer, give it a unique name using this method, then
set the `iconImageName` property of an `MGLSymbolStyleLayer` object to that
name.
-
+
@param image The image for the name.
@param name The name of the image to set to the style.
*/
@@ -429,13 +429,13 @@ MGL_EXPORT
/**
Removes a name and its associated image from the style.
-
+
@note Names and their associated images are not guaranteed to exist across
styles or different versions of the same style. Applications that use this
API must first set the style URL to an explicitly versioned style using a
convenience method like `+[MGLStyle outdoorsStyleURLWithVersion:]`,
- `MGLMapView`'s “Style URL” inspectable in Interface Builder, or a manually
- constructed `NSURL`. This approach also avoids image name changes that will
+ `MGLMapView`’s “Style URL” inspectable in Interface Builder, or a manually
+ constructed `NSURL`. This approach also avoids image name changes that will
occur in the default style over time.
@param name The name of the image to remove.
@@ -446,7 +446,7 @@ MGL_EXPORT
/**
The duration in seconds to animate any changes to the style URL or to layout and paint attributes.
-
+
By default, this property is set to zero seconds, so any changes take effect without animation.
*/
@property (nonatomic) NSTimeInterval transitionDuration;
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 78c719050c..bcb8100800 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -217,7 +217,7 @@ static NSURL *MGLStyleURL_emerald;
if (![source isKindOfClass:[MGLTileSource class]]) {
continue;
}
-
+
NSArray *tileSetInfos = [source attributionInfosWithFontSize:fontSize linkColor:linkColor];
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
}
@@ -321,7 +321,7 @@ static NSURL *MGLStyleURL_emerald;
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)mbglLayer
{
NSParameterAssert(mbglLayer);
-
+
NSString *identifier = @(mbglLayer->getID().c_str());
MGLStyleLayer *styleLayer;
if (auto fillLayer = mbglLayer->as<mbgl::style::FillLayer>()) {
@@ -438,7 +438,7 @@ static NSURL *MGLStyleURL_emerald;
@"Make sure sibling was obtained using -[MGLStyle layerWithIdentifier:].",
sibling];
}
-
+
auto layers = self.mapView.mbglMap->getLayers();
std::string siblingIdentifier = sibling.identifier.UTF8String;
NSUInteger index = 0;
@@ -448,7 +448,7 @@ static NSURL *MGLStyleURL_emerald;
}
index++;
}
-
+
[self willChangeValueForKey:@"layers"];
if (index + 1 > layers.size()) {
[NSException raise:NSInvalidArgumentException
diff --git a/platform/darwin/src/MGLStyleLayer.h b/platform/darwin/src/MGLStyleLayer.h
index ac40545398..55f1a56490 100644
--- a/platform/darwin/src/MGLStyleLayer.h
+++ b/platform/darwin/src/MGLStyleLayer.h
@@ -9,11 +9,11 @@ NS_ASSUME_NONNULL_BEGIN
`MGLStyleLayer` is an abstract base class for style layers. A style layer
manages the layout and appearance of content at a specific z-index in a style.
An `MGLStyle` object consists of one or more `MGLStyleLayer` objects.
-
+
Each style layer defined by the style JSON file is represented at runtime by an
`MGLStyleLayer` object, which you can use to refine the map’s appearance. You
can also add and remove style layers dynamically.
-
+
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of
`MGLBackgroundStyleLayer` and the concrete subclasses of
@@ -28,11 +28,16 @@ MGL_EXPORT
/**
Returns a style layer object initialized with the given identifier.
-
+
+ The default implementation of this initializer in MGLStyleLayer creates an
+ invalid style layer. Call this initializer on `MGLBackgroundStyleLayer` or one of
+ the concrete subclasses of `MGLForegroundStyleLayer` to create a valid style
+ layer.
+
After initializing and configuring the style layer, add it to a map view’s
style using the `-[MGLStyle addLayer:]` or
`-[MGLStyle insertLayer:belowLayer:]` method.
-
+
@param identifier A string that uniquely identifies the layer in the style to
which it is added.
@return An initialized style layer.
diff --git a/platform/darwin/src/MGLStyleLayer.h.ejs b/platform/darwin/src/MGLStyleLayer.h.ejs
index 8ffed66b54..f0a4ba64a3 100644
--- a/platform/darwin/src/MGLStyleLayer.h.ejs
+++ b/platform/darwin/src/MGLStyleLayer.h.ejs
@@ -5,7 +5,7 @@
const paintProperties = locals.paintProperties;
const enumProperties = locals.enumProperties;
-%>
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -22,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
<% if (property.type == "enum") { -%>
/**
<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
-
+
Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
property.
*/
@@ -41,7 +41,7 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% if (property.type == "enum") { -%>
/**
<%- propertyDoc(property.name, property, type, 'enum').wrap(80, 1) %>
-
+
Values of this type are used in the `MGL<%- camelize(type) %>StyleLayer.<%- camelizeWithLeadingLowercase(property.name) %>`
property.
*/
@@ -63,15 +63,15 @@ typedef NS_ENUM(NSUInteger, MGL<%- camelize(property.name) %>) {
<% } else { -%>
/**
<%- doc.wrap(80, 1) %>
-
+
You can access an existing <%- type %> style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new <%- type %> style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
```
*/
diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm
index 97f8f86b26..47f41e0388 100644
--- a/platform/darwin/src/MGLStyleLayer.mm
+++ b/platform/darwin/src/MGLStyleLayer.mm
@@ -61,7 +61,7 @@
- (float)minimumZoomLevel
{
MGLAssertStyleLayerIsValid();
-
+
return self.rawLayer->getMinZoom();
}
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index 9445c3cf21..24aff7fca8 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -4,7 +4,7 @@
const paintProperties = locals.paintProperties;
const enumProperties = locals.enumProperties;
-%>
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -95,7 +95,7 @@ namespace mbgl {
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -150,8 +150,9 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -176,24 +177,42 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
- self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
+<% if (property["property-function"]) { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>);
<% } else { -%>
+<% if (property.type == "enum") { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toEnumPropertyValue(<%- objCName(property) %>);
+<% } else if (property.function == "piecewise-constant") { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
- self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
+<% } else { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>);
+<% } -%>
<% } -%>
+ self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
+ auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>();
+<% if (property["property-function"]) { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(propertyValue);
+<% } else { -%>
<% if (property.type == "enum") { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
+<% } -%>
}
<% if (property.original) { -%>
@@ -214,24 +233,42 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property.type == "enum") { -%>
- auto mbglValue = MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumPropertyValue(<%- objCName(property) %>);
- self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
+<% if (property["property-function"]) { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenPropertyValue(<%- objCName(property) %>);
<% } else { -%>
+<% if (property.type == "enum") { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toEnumPropertyValue(<%- objCName(property) %>);
+<% } else if (property.function == "piecewise-constant") { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue(<%- objCName(property) %>);
- self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
+<% } else { -%>
+ auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toInterpolatablePropertyValue(<%- objCName(property) %>);
+<% } -%>
<% } -%>
+ self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
}
- (MGLStyleValue<<%- propertyType(property, true) %>> *)<%- objCGetter(property) %> {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>() ?: self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>();
+ auto propertyValue = self.rawLayer->get<%- camelize(originalPropertyName(property)) %>();
+<% if (property["property-function"]) { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toDataDrivenStyleValue(propertyValue);
+<% } else { -%>
<% if (property.type == "enum") { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
return MGLStyleValueTransformer<<%- mbglType(property) %>, NSValue *, <%- mbglType(property) %>, MGL<%- camelize(property.name) %>>().toEnumStyleValue(propertyValue);
<% } else { -%>
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(self.rawLayer->getDefault<%- camelize(originalPropertyName(property)) %>());
+ }
return MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toStyleValue(propertyValue);
<% } -%>
+<% } -%>
}
<% if (property.original) { -%>
diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h
index 8f1cdfb4a1..b5d709a7af 100644
--- a/platform/darwin/src/MGLStyleLayer_Private.h
+++ b/platform/darwin/src/MGLStyleLayer_Private.h
@@ -53,9 +53,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Removes the mbgl style layer that this object represents from the mbgl map.
-
+
When a mbgl style layer is removed, ownership of the object is transferred back
- to the `MGLStyleLayer` instance and the unique_ptr reference is valid again. It
+ to the `MGLStyleLayer` instance and the unique_ptr reference is valid again. It
is safe to add the layer back to the style after it is removed.
*/
- (void)removeFromMapView:(MGLMapView *)mapView;
diff --git a/platform/darwin/src/MGLStyleValue.h b/platform/darwin/src/MGLStyleValue.h
index 5b6528f6fd..2ce2eae89a 100644
--- a/platform/darwin/src/MGLStyleValue.h
+++ b/platform/darwin/src/MGLStyleValue.h
@@ -2,20 +2,91 @@
#import <CoreGraphics/CoreGraphics.h>
#import "MGLFoundation.h"
+#import "MGLTypes.h"
NS_ASSUME_NONNULL_BEGIN
/**
+ Options for `MGLStyleFunction` objects.
+ */
+typedef NSString *MGLStyleFunctionOption NS_STRING_ENUM;
+
+/**
+ An `NSNumber` object containing an integer that determines the style function's
+ exponential interpolation base.
+
+ The exponential interpolation base controls the rate at which the function’s
+ output values increase. A value of 1 causes the function to increase linearly
+ by zoom level. A higher exponential interpolation base causes the function’s
+ output values to vary exponentially, increasing more rapidly towards the high
+ end of the function’s range. The default value of this property is 1, for a
+ linear curve.
+
+ This attribute corresponds to the
+ <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#function-base"><code>base</code></a>
+ function property in the Mapbox Style Specification.
+
+ This option only applies to functions that use an
+ `MGLInterpolationModeExponential` interpolation mode that are assigned to
+ interpolatable style layer properties.
+ */
+extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase;
+
+/**
+ An `MGLStyleConstantValue` object that specifies a default value that a style
+ function can use when it can't otherwise determine a value.
+
+ A default value can be used to set the value of a style layer property that
+ is not otherwise set by a function. For example, a source function with a
+ `MGLInterpolationModeCategorical` interpolation mode with stops that specify
+ color values to use based on a feature's attributes would set any feature
+ that does not have attributes that match the stop key values to this
+ default value.
+
+ This option only applies to `MGLSourceStyleFunction` and
+ `MGLCompositeStyleFunction` functions.
+ */
+extern MGL_EXPORT const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue;
+
+/**
+ The modes used to interpolate property values between map zoom level changes
+ or over a range of feature attribute values.
+ */
+typedef NS_ENUM(NSUInteger, MGLInterpolationMode) {
+ /**
+ Values between two stops are interpolated exponentially or linearly if the
+ `MGLStyleFunctionOptionInterpolationBase` is 1.
+ */
+ MGLInterpolationModeExponential = 0,
+ /**
+ Values between two stops are not interpolated. Instead, properties are set
+ to the value of the stop just less than the function input.
+ */
+ MGLInterpolationModeInterval,
+ /**
+ Values between two stops are not interpolated. Instead, properties are set
+ to the value of the stop equal to the function input's key value.
+ */
+ MGLInterpolationModeCategorical,
+ /**
+ Values between two stops are not interpolated. Instead, values are set
+ to their input value.
+ */
+ MGLInterpolationModeIdentity
+};
+
+/**
An `MGLStyleValue` object is a generic container for a style attribute value.
The layout and paint attribute properties of `MGLStyleLayer` can be set to
`MGLStyleValue` objects.
-
+
The `MGLStyleValue` class itself represents a class cluster. Under the hood, a
particular `MGLStyleValue` object may be either an `MGLStyleConstantValue` to
- represent a constant value or an `MGLStyleFunction` to represent a value
- function. Do not initialize an `MGLStyleValue` object directly; instead, use
- one of the class factory methods to create an `MGLStyleValue` object.
-
+ represent a constant value or one of the concrete subclasses of
+ `MGLStyleFunction` to represent a value function. Do not initialize an
+ `MGLStyleValue` object directly; instead, use one of the class factory methods
+ to create an `MGLStyleValue` object.
+
The `MGLStyleValue` class takes a generic parameter `T` that indicates the
Foundation class being wrapped by this class. Common values for `T` include:
@@ -34,31 +105,78 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleConstantValue` object containing a raw value.
-
+
@param rawValue The constant value contained by the object.
@return An `MGLStyleConstantValue` object containing `rawValue`, which is
treated as a constant value.
*/
+ (instancetype)valueWithRawValue:(T)rawValue;
+#pragma mark Function values
+
/**
- Creates and returns an `MGLStyleFunction` object representing a linear zoom
- level function with any number of stops.
-
+ Creates and returns an `MGLCameraStyleFunction` object representing a linear camera
+ function with one or more stops.
+
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given stops.
+ @return An `MGLCameraStyleFunction` object with the given stops.
*/
-+ (instancetype)valueWithStops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)valueWithStops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
/**
- Creates and returns an `MGLStyleFunction` object representing a zoom level
- function with an exponential interpolation base and any number of stops.
-
+ Creates and returns an `MGLCameraStyleFunction` object representing a camera
+ function with an exponential interpolation base and one or more stops.
+
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given interpolation base and stops.
+ @return An `MGLCameraStyleFunction` object with the given interpolation base and stops.
+ */
++ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
+
+/**
+ Creates and returns an `MGLCameraStyleFunction` object representing a camera function
+ with one or more stops.
+
+ @param interpolationMode The mode used to interpolate property values between
+ map zoom level changes.
+ @param cameraStops A dictionary associating zoom levels with style values.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLCameraStyleFunction` object with the given interpolation mode,
+ camera stops, and options.
*/
-+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)cameraStops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
+
+/**
+ Creates and returns an `MGLSourceStyleFunction` object representing a source function.
+
+ @param interpolationMode The mode used to interpolate property values over a
+ range of feature attribute values.
+ @param sourceStops A dictionary associating feature attributes with style values.
+ @param attributeName Specifies the feature attribute to take as the function
+ input.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLSourceStyleFunction` object with the given interpolation mode,
+ source stops, attribute name, and options.
+ */
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)sourceStops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
+
+/**
+ Creates and returns an `MGLCompositeStyleFunction` object representing a composite
+ function.
+
+ @param interpolationMode The mode used to interpolate property values over a
+ range of feature attribute values for each outer zoom level.
+ @param sourceStops A dictionary associating feature attributes with style values.
+ @param attributeName Specifies the feature attribute to take as the function
+ input.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLCompositeStyleFunction` object with the given interpolation mode,
+ composite stops, attribute name, and options.
+ */
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *)compositeStops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
@end
@@ -67,7 +185,7 @@ MGL_EXPORT
value that remains constant as the zoom level changes. The layout and paint
attribute properties of `MGLStyleLayer` objects can be set to
`MGLStyleConstantValue` objects.
-
+
The `MGLStyleConstantValue` class takes a generic parameter `T` that indicates
the Foundation class being wrapped by this class.
*/
@@ -78,7 +196,7 @@ MGL_EXPORT
/**
Creates and returns an `MGLStyleConstantValue` object containing a raw value.
-
+
@param rawValue The constant value contained by the object.
@return An `MGLStyleConstantValue` object containing `rawValue`, which is
treated as a constant value.
@@ -91,7 +209,7 @@ MGL_EXPORT
/**
Returns an `MGLStyleConstantValue` object containing a raw value.
-
+
@param rawValue The value contained by the receiver.
@return An `MGLStyleConstantValue` object containing `rawValue`.
*/
@@ -107,11 +225,16 @@ MGL_EXPORT
@end
/**
- An `MGLStyleFunction` is a value function defining a style value that changes
- as the zoom level changes. The layout and paint attribute properties of an
- `MGLStyleLayer` object can be set to `MGLStyleFunction` objects. Use a zoom
- level function to create the illusion of depth and control data density.
+ An `MGLStyleFunction` is a is an abstract superclass for functions that are
+ defined by an `MGLCameraStyleFunction`, `MGLSourceStyleFunction`, or
+ `MGLCompositeStyleFunction` object.
+ Do not create instances of this class directly, and do not create your own
+ subclasses of this class. Instead, use one of the class factory methods in
+ `MGLStyleValue` to create instances of the following concrete subclasses:
+ `MGLCameraStyleFunction`, `MGLSourceStyleFunction`, and
+ `MGLCompositeStyleFunction`.
+
The `MGLStyleFunction` class takes a generic parameter `T` that indicates the
Foundation class being wrapped by this class.
*/
@@ -121,52 +244,108 @@ MGL_EXPORT
#pragma mark Creating a Style Function
/**
- Creates and returns an `MGLStyleFunction` object representing a linear zoom
- level function with any number of stops.
-
+ Creates and returns an `MGLCameraStyleFunction` object representing a camera
+ function with a linear interpolation curve.
+
+ @note Do not create function instances using this method unless it is required
+ for backwards compatiblity with your application code.
+
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given stops.
+ @return An `MGLCameraStyleFunction` object with the given stops.
*/
-+ (instancetype)functionWithStops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)functionWithStops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
/**
- Creates and returns an `MGLStyleFunction` object representing a zoom level
- function with an exponential interpolation base and any number of stops.
-
+ Creates and returns an `MGLCameraStyleFunction` object representing a camera
+ function with an interpolation curve controlled by the provided interpolation
+ base.
+
+ @note Do not create function instances using this method unless it is required
+ for backwards compatiblity with your application code.
+
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
- @return An `MGLStyleFunction` object with the given interpolation base and stops.
+ @return An `MGLCameraStyleFunction` object with the given interpolation base and stops.
*/
-+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops;
++ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
#pragma mark Initializing a Style Function
/**
- Returns an `MGLStyleFunction` object representing a zoom level function with an
- exponential interpolation base and any number of stops.
+ Returns an `MGLStyleFunction` object representing a camera function. If the
+ function is set as a style layer property value, it will be interpreted
+ as a camera function with an interpolation curve controlled by the provided
+ interpolation base.
+ @note Do not create instances of `MGLStyleFunction` unless it is required for
+ backwards compatiblity with your application code. You should create and use
+ instances of `MGLCameraStyleFunction` to specify how properties will
+ be visualized at different zoom levels.
+
@param interpolationBase The exponential base of the interpolation curve.
@param stops A dictionary associating zoom levels with style values.
@return An `MGLStyleFunction` object with the given interpolation base and stops.
*/
-- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary<NSNumber *, MGLStyleValue<T> *> *)stops NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NS_DICTIONARY_OF(NSNumber *, MGLStyleValue<T> *) *)stops __attribute__((deprecated("Use +[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]")));
#pragma mark Accessing the Parameters of a Function
/**
+ The modes used to interpolate property values between map zoom level changes or
+ over a range of feature attribute values.
+ */
+@property (nonatomic) MGLInterpolationMode interpolationMode;
+
+/**
+ A dictionary associating zoom levels with style values.
+ */
+@property (nonatomic, copy, nullable) NSDictionary *stops;
+
+/**
The exponential interpolation base of the function’s interpolation curve.
- The exponential interpolation base controls the rate at which the function’s output values
- increase. A value of 1 causes the function to increase linearly by zoom level.
- A higher exponential interpolation base causes the function’s output values to vary
- exponentially, increasing more rapidly towards the high end of the function’s
- range. The default value of this property is 1, for a linear curve.
+ @note This property specifies the exponential base of the interpolation curve
+ of `MGLCameraStyleFunction` and `MGLSourceStyleFunction` functions that use
+ a `MGLInterpolationModeExponential` `interpolationMode`. Otherwise, it is
+ ignored.
*/
@property (nonatomic) CGFloat interpolationBase;
+@end
+
+/**
+ An `MGLCameraStyleFunction` is a value function defining a style value that changes
+ as the zoom level changes. The layout and paint attribute properties of an
+ `MGLStyleLayer` object can be set to `MGLCameraStyleFunction` objects. Use a camera
+ function to create the illusion of depth and control data density.
+
+ The `MGLCameraStyleFunction` class takes a generic parameter `T` that indicates the
+ Foundation class being wrapped by this class.
+ */
+MGL_EXPORT
+@interface MGLCameraStyleFunction<T> : MGLStyleFunction<T>
+
+#pragma mark Creating a Camera Function
+
+/**
+ Creates and returns an `MGLCameraStyleFunction` object representing a camera
+ function with one or more stops.
+
+ @param interpolationMode The mode used to interpolate property values between
+ map zoom level changes.
+ @param stops A dictionary associating zoom levels with style values.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLCameraStyleFunction` object with the given interpolation mode,
+ camera stops, and options.
+ */
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)stops options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
+
+#pragma mark Accessing the Parameters of a Camera Function
+
/**
A dictionary associating zoom levels with style values.
-
+
Each of the function’s stops is represented by one key-value pair in the
dictionary. Each key in the dictionary is an `NSNumber` object containing a
floating-point zoom level. Each value in the dictionary is an `MGLStyleValue`
@@ -174,7 +353,128 @@ MGL_EXPORT
associated zoom level. An `MGLStyleFunction` object may not be used recursively
as a stop value.
*/
-@property (nonatomic, copy) NSDictionary<NSNumber *, MGLStyleValue<T> *> *stops;
+@property (nonatomic, copy) NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *stops;
+
+@end
+
+/**
+ An `MGLSourceStyleFunction` is a value function defining a style value that
+ changes with its properties. The layout and paint attribute properties of an
+ `MGLStyleLayer` object can be set to `MGLSourceStyleFunction` objects.
+ Use source functions to visually differentate types of features within the same
+ layer or create data visualizations.
+
+ The `MGLSourceStyleFunction` class takes a generic parameter `T` that indicates the
+ Foundation class being wrapped by this class.
+ */
+MGL_EXPORT
+@interface MGLSourceStyleFunction<T> : MGLStyleFunction<T>
+
+#pragma mark Creating a Source Function
+
+/**
+ Creates and returns an `MGLSourceStyleFunction` object representing a source
+ function.
+
+ @param interpolationMode The mode used to interpolate property values over a
+ range of feature attribute values.
+ @param sourceStops A dictionary associating feature attributes with style values.
+ @param attributeName Specifies the feature attribute to take as the function
+ input.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLSourceStyleFunction` object with the given interpolation mode,
+ source stops, attribute name, and options.
+*/
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(nullable NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
+
+#pragma mark Accessing the Parameters of a Source Function
+
+/**
+ A string that specifies the feature attribute key whose value be used as the function
+ input.
+*/
+@property (nonatomic, copy) NSString *attributeName;
+
+/**
+ A dictionary associating attribute values with style values.
+
+ Each of the function’s stops is represented by one key-value pair in the
+ dictionary. Each key in the dictionary is an object representing a feature
+ attribute key or interpolation stop. Each value in the dictionary is an
+ `MGLStyleValue` object containing the value to use when the function is given
+ the associated attribute key. An `MGLStyleFunction` object may not be used
+ recursively as a stop value.
+ */
+@property (nonatomic, copy, nullable) NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *stops;
+
+/**
+ An `MGLStyleValue` object containing the default value to use when there is
+ no input to provide to the function.
+ */
+@property (nonatomic, nullable) MGLStyleValue<T> *defaultValue;
+
+@end
+
+/**
+ An `MGLCompositeStyleFunction` is a value function defining a style value that
+ changes with the feature attributes at each map zoom level. The layout and paint
+ attribute properties of an `MGLStyleLayer` object can be set to
+ `MGLCompositeStyleFunction` objects. Use composite functions to allow the
+ appearance of a map feature to change with both its attributes and the map zoom
+ level.
+
+ The `MGLCompositeStyleFunction` class takes a generic parameter `T` that indicates the
+ Foundation class being wrapped by this class.
+ */
+MGL_EXPORT
+@interface MGLCompositeStyleFunction<T> : MGLStyleFunction<T>
+
+#pragma mark Creating a Composite Function
+
+/**
+ Creates and returns an `MGLCompositeStyleFunction` object representing a composite
+ function.
+
+ @param interpolationMode The mode used to interpolate property values over a
+ range of feature attribute values for each outer zoom level.
+ @param sourceStops A dictionary associating feature attributes with style values.
+ @param attributeName Specifies the feature attribute to take as the function
+ input.
+ @param options A dictionary containing `MGLStyleFunctionOption` values that
+ specify how a function is applied.
+ @return An `MGLCompositeStyleFunction` object with the given interpolation mode,
+ composite stops, attribute name, and options.
+ */
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *)stops attributeName:(NSString *)attributeName options:(nullable NS_DICTIONARY_OF(MGLStyleFunctionOption, id) *)options;
+
+#pragma mark Accessing the Parameters of a Composite Function
+
+/**
+ A string that specifies the feature attribute key whose value be used as the function
+ input.
+ */
+@property (nonatomic, copy) NSString *attributeName;
+
+/**
+ A dictionary associating attribute values with style values.
+
+ Each of the function’s stops is represented by one key-value pair in the
+ dictionary. Each key in the dictionary is an `NSNumber` object containing a
+ floating-point zoom level. Each value in the dictionary is an inner nested
+ dictionary. Each key in the nested dictionary is an object representing a feature
+ attribute key or interpolation stop. Each value in the nested dictionary is an
+ `MGLStyleValue` object containing the value to use when the function is given
+ the associated attribute key. An `MGLStyleFunction` object may not be used
+ recursively as a value inside the nested dictionary.
+ */
+@property (nonatomic, copy) NS_DICTIONARY_OF(id, NS_DICTIONARY_OF(id, MGLStyleValue<T> *) *) *stops;
+
+/**
+ An `MGLStyleValue` object containing the default value to use when there is
+ no input to provide to the function.
+ */
+@property (nonatomic, nullable) MGLStyleValue<T> *defaultValue;
@end
diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm
index 9e77114378..020dc27d6a 100644
--- a/platform/darwin/src/MGLStyleValue.mm
+++ b/platform/darwin/src/MGLStyleValue.mm
@@ -1,5 +1,8 @@
#import "MGLStyleValue_Private.h"
+const MGLStyleFunctionOption MGLStyleFunctionOptionInterpolationBase = @"MGLStyleFunctionOptionInterpolationBase";
+const MGLStyleFunctionOption MGLStyleFunctionOptionDefaultValue = @"MGLStyleFunctionOptionDefaultValue";
+
@implementation MGLStyleValue
+ (instancetype)valueWithRawValue:(id)rawValue {
@@ -7,11 +10,23 @@
}
+ (instancetype)valueWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [MGLStyleFunction functionWithInterpolationBase:interpolationBase stops:stops];
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
}
+ (instancetype)valueWithStops:(NSDictionary *)stops {
- return [MGLStyleFunction functionWithStops:stops];
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:nil];
+}
+
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode cameraStops:(NSDictionary *)cameraStops options:(NSDictionary *)options {
+ return [MGLCameraStyleFunction functionWithInterpolationMode:interpolationMode stops:cameraStops options:options];
+}
+
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode sourceStops:(NSDictionary *)sourceStops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ return [MGLSourceStyleFunction functionWithInterpolationMode:interpolationMode stops:sourceStops attributeName:attributeName options:options];
+}
+
++ (instancetype)valueWithInterpolationMode:(MGLInterpolationMode)interpolationMode compositeStops:(NSDictionary *)compositeStops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ return [MGLCompositeStyleFunction functionWithInterpolationMode:interpolationMode stops:compositeStops attributeName:attributeName options:options];
}
@end
@@ -49,44 +64,245 @@
@implementation MGLStyleFunction
-+ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
- return [[self alloc] initWithInterpolationBase:interpolationBase stops:stops];
++ (instancetype)functionWithStops:(NSDictionary *)stops {
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:nil];
}
-+ (instancetype)functionWithStops:(NSDictionary *)stops {
- return [[self alloc] initWithInterpolationBase:1 stops:stops];
++ (instancetype)functionWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
}
- (instancetype)init {
- return [self initWithInterpolationBase:1 stops:@{}];
+ if (self = [super init]) {
+ self.interpolationBase = 1.0;
+ self.stops = @{};
+ }
+ return self;
}
- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
if (self = [super init]) {
- if (!stops.count)
- {
- [NSException raise:NSInvalidArgumentException format:@"%@ requires at least one stop.", self];
- }
- _interpolationBase = interpolationBase;
- _stops = stops;
+ self.interpolationBase = interpolationBase;
+ self.stops = stops;
}
return self;
}
- (NSString *)description {
- return [NSString stringWithFormat:@"<%@: %p, interpolationBase = %f; stops = %@>",
+ return [NSString stringWithFormat:@"<%@: %p, \
+ stops = %@, \
+ interpolationBase = %f>",
NSStringFromClass([self class]), (void *)self,
- self.interpolationBase,
- self.stops];
+ self.stops,
+ self.interpolationBase];
}
- (BOOL)isEqual:(MGLStyleFunction *)other {
- return ([other isKindOfClass:[self class]] && other.interpolationBase == self.interpolationBase
- && [other.stops isEqualToDictionary:self.stops]);
+ return ([other isKindOfClass:[self class]]
+ && [other.stops isEqualToDictionary:self.stops]
+ && other.interpolationBase == self.interpolationBase);
+}
+
+- (NSUInteger)hash {
+ return self.stops.hash + @(self.interpolationBase).hash;
+}
+
+@end
+
+@implementation MGLCameraStyleFunction
+
+@dynamic stops;
+
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options {
+ return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops options:options];
+}
+
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
+}
+
+- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops options:(NSDictionary *)options {
+ if (![stops count]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Camera functions must have at least one stop."];
+ return {};
+ }
+
+ if (self == [super init]) {
+ self.interpolationMode = interpolationMode;
+ self.stops = stops;
+
+ if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
+ if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
+ NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
+ self.interpolationBase = [value floatValue];
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
+ }
+ }
+ }
+ return self;
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"<%@: %p, \
+ interpolationMode = %lu, \
+ stops = %@, \
+ interpolationBase = %f>",
+ NSStringFromClass([self class]), (void *)self,
+ (unsigned long)self.interpolationMode,
+ self.stops,
+ self.interpolationBase];
+}
+
+- (BOOL)isEqual:(MGLCameraStyleFunction *)other {
+ return ([other isKindOfClass:[self class]]
+ && other.interpolationMode == self.interpolationMode
+ && [other.stops isEqualToDictionary:self.stops]
+ && other.interpolationBase == self.interpolationBase);
+}
+
+- (NSUInteger)hash {
+ return @(self.interpolationMode).hash + self.stops.hash + @(self.interpolationBase).hash;
+}
+
+@end
+
+@implementation MGLSourceStyleFunction
+
+@dynamic stops;
+
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
+}
+
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
+}
+
+- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ if (self == [super init]) {
+ self.interpolationMode = interpolationMode;
+ self.stops = stops;
+ _attributeName = attributeName;
+
+ if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
+ if ([options[MGLStyleFunctionOptionDefaultValue] isKindOfClass:[MGLStyleValue class]]) {
+ MGLStyleValue *value = (MGLStyleValue *)options[MGLStyleFunctionOptionDefaultValue];
+ _defaultValue = value;
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"Default value must be an MGLStyleValue"];
+ }
+ }
+
+ if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
+ if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
+ NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
+ self.interpolationBase = [value floatValue];
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
+ }
+ }
+ }
+ return self;
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"<%@: %p, \
+ interpolationMode = %lu, \
+ stops = %@, \
+ attributeName = %@, \
+ defaultValue = %@, \
+ interpolationBase = %f>",
+ NSStringFromClass([self class]),
+ (void *)self,
+ (unsigned long)self.interpolationMode,
+ self.stops,
+ self.attributeName,
+ self.defaultValue,
+ self.interpolationBase];
+}
+
+- (BOOL)isEqual:(MGLSourceStyleFunction *)other {
+ return ([other isKindOfClass:[self class]]
+ && other.interpolationMode == self.interpolationMode
+ && ((self.stops && [other.stops isEqualToDictionary:self.stops]) || (!self.stops && !other.stops))
+ && [other.attributeName isEqual:self.attributeName]
+ && ((self.defaultValue && [other.defaultValue isEqual:self.defaultValue]) || (!self.defaultValue && !other.defaultValue))
+ && other.interpolationBase == self.interpolationBase);
+}
+
+- (NSUInteger)hash {
+ return @(self.interpolationMode).hash + self.stops.hash + self.attributeName.hash + self.defaultValue.hash + @(self.interpolationBase).hash;
+}
+
+@end
+
+@implementation MGLCompositeStyleFunction
+
+@dynamic stops;
+
++ (instancetype)functionWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ return [[self alloc] initWithInterpolationMode:interpolationMode stops:stops attributeName:attributeName options:options];
+}
+
+- (instancetype)initWithInterpolationBase:(CGFloat)interpolationBase stops:(NSDictionary *)stops {
+ return [self initWithInterpolationMode:MGLInterpolationModeExponential stops:stops attributeName:@"" options:@{MGLStyleFunctionOptionInterpolationBase: @(interpolationBase)}];
+}
+
+- (instancetype)initWithInterpolationMode:(MGLInterpolationMode)interpolationMode stops:(NSDictionary *)stops attributeName:(NSString *)attributeName options:(NSDictionary *)options {
+ if (self == [super init]) {
+ self.interpolationMode = interpolationMode;
+ self.stops = stops;
+ _attributeName = attributeName;
+
+ if ([options.allKeys containsObject:MGLStyleFunctionOptionDefaultValue]) {
+ if ([options[MGLStyleFunctionOptionDefaultValue] isKindOfClass:[MGLStyleValue class]]) {
+ MGLStyleValue *value = (MGLStyleValue *)options[MGLStyleFunctionOptionDefaultValue];
+ _defaultValue = value;
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"Default value must be an MGLStyleValue"];
+ }
+ }
+
+ if ([options.allKeys containsObject:MGLStyleFunctionOptionInterpolationBase]) {
+ if ([options[MGLStyleFunctionOptionInterpolationBase] isKindOfClass:[NSNumber class]]) {
+ NSNumber *value = (NSNumber *)options[MGLStyleFunctionOptionInterpolationBase];
+ self.interpolationBase = [value floatValue];
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"Interpolation base must be an NSNumber that represents a CGFloat."];
+ }
+ }
+ }
+ return self;
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"<%@: %p, \
+ interpolationMode = %lu, \
+ stops = %@, \
+ attributeName = %@, \
+ defaultValue = %@, \
+ interpolationBase = %f>",
+ NSStringFromClass([self class]), (void *)self,
+ (unsigned long)self.interpolationMode,
+ self.stops,
+ self.attributeName,
+ self.defaultValue,
+ self.interpolationBase];
+}
+
+- (BOOL)isEqual:(MGLCompositeStyleFunction *)other {
+ return ([other isKindOfClass:[self class]]
+ && other.interpolationMode == self.interpolationMode
+ && [other.stops isEqualToDictionary:self.stops]
+ && [other.attributeName isEqual:self.attributeName]
+ && ((self.defaultValue && [other.defaultValue isEqual:self.defaultValue]) || (!self.defaultValue && !other.defaultValue))
+ && other.interpolationBase == self.interpolationBase);
}
- (NSUInteger)hash {
- return self.interpolationBase + self.stops.hash;
+ return @(self.interpolationMode).hash + self.stops.hash + self.attributeName.hash + @(self.interpolationBase).hash;
}
@end
diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h
index 2c3de3fb74..3a5ce8d474 100644
--- a/platform/darwin/src/MGLStyleValue_Private.h
+++ b/platform/darwin/src/MGLStyleValue_Private.h
@@ -4,64 +4,108 @@
#import "NSValue+MGLStyleAttributeAdditions.h"
#import "MGLTypes.h"
+
+#import "MGLConversion.h"
+#include <mbgl/style/conversion/data_driven_property_value.hpp>
+#include <mbgl/style/conversion.hpp>
+
#import <mbgl/util/enum.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
+
+#include <mbgl/util/interpolate.hpp>
+
#if TARGET_OS_IPHONE
#import "UIColor+MGLAdditions.h"
#else
#import "NSColor+MGLAdditions.h"
#endif
-#include <array>
-
template <typename MBGLType, typename ObjCType, typename MBGLElement = MBGLType, typename ObjCEnum = ObjCType>
class MGLStyleValueTransformer {
public:
-
+
+ // Convert an mbgl property value into an mgl style value
MGLStyleValue<ObjCType> *toStyleValue(const mbgl::style::PropertyValue<MBGLType> &mbglValue) {
- if (mbglValue.isConstant()) {
- return toStyleConstantValue(mbglValue.asConstant());
- } else if (mbglValue.isFunction()) {
- return toStyleFunction(mbglValue.asFunction());
- } else {
- return nil;
- }
+ PropertyValueEvaluator evaluator;
+ return mbglValue.evaluate(evaluator);
}
+ // Convert an mbgl data driven property value into an mgl style value
+ MGLStyleValue<ObjCType> *toDataDrivenStyleValue(const mbgl::style::DataDrivenPropertyValue<MBGLType> &mbglValue) {
+ PropertyValueEvaluator evaluator;
+ return mbglValue.evaluate(evaluator);
+ }
+
+ // Convert an mbgl property value containing an enum into an mgl style value
template <typename MBGLEnum = MBGLType,
class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
typename MGLEnum = ObjCEnum,
class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
MGLStyleValue<ObjCType> *toEnumStyleValue(const mbgl::style::PropertyValue<MBGLEnum> &mbglValue) {
- if (mbglValue.isConstant()) {
- return toEnumStyleConstantValue<>(mbglValue.asConstant());
- } else if (mbglValue.isFunction()) {
- const auto &mbglStops = mbglValue.asFunction().getStops();
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()];
- for (const auto &mbglStop : mbglStops) {
- stops[@(mbglStop.first)] = toEnumStyleConstantValue<>(mbglStop.second);
- }
- return [MGLStyleFunction<NSValue *> functionWithInterpolationBase:mbglValue.asFunction().getBase() stops:stops];
+ EnumPropertyValueEvaluator<MBGLEnum, ObjCEnum> evaluator;
+ return mbglValue.evaluate(evaluator);
+ }
+
+ // Convert an mgl style value into a non interpolatable (camera with interval stops) mbgl property value
+ mbgl::style::PropertyValue<MBGLType> toPropertyValue(MGLStyleValue<ObjCType> *value) {
+ if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"This property can only be set to camera functions. Use +[MGLStyleValue cameraFunctionValueWithinterpolationMode:stops:options:] instead."];
+ return {};
+ }
+
+ if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
+ return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value);
+ } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
+ // Intentionally ignore the stop type set by the developer becuase non interpolatable property values
+ // can only have interval stops. This also allows for backwards compatiblity when the developer uses
+ // a deprecated MGLStyleValue method (that used to create an MGLStyleFunction) to create a function
+ // for properties that are piecewise-constant (i.e. enum, bool, string)
+ return toMBGLIntervalCameraFunction(cameraStyleFunction);
+ } else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
+ MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
+ return toMBGLIntervalCameraFunction(styleFunction);
+ } else if (value) {
+ [NSException raise:@"MGLAbstractClassException" format:
+ @"The style value %@ cannot be applied to the style. "
+ @"Make sure the style value was created as a member of a concrete subclass of MGLStyleValue.",
+ NSStringFromClass([value class])];
+ return {};
} else {
- return nil;
+ return {};
}
}
- mbgl::style::PropertyValue<MBGLType> toPropertyValue(MGLStyleValue<ObjCType> *value) {
+ // Convert an mgl style value into a non interpolatable (camera with exponential or interval stops) mbgl property value
+ mbgl::style::PropertyValue<MBGLType> toInterpolatablePropertyValue(MGLStyleValue<ObjCType> *value) {
+ if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"This property can only be set to camera functions. Use +[MGLStyleValue cameraFunctionValueWithinterpolationMode:stops:options:] instead."];
+ return {};
+ }
+
if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
- MBGLType mbglValue;
- getMBGLValue([(MGLStyleConstantValue<ObjCType> *)value rawValue], mbglValue);
- return mbglValue;
- } else if ([value isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction<ObjCType> *function = (MGLStyleFunction<ObjCType> *)value;
- __block std::vector<std::pair<float, MBGLType>> mbglStops;
- [function.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
- NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
- auto mbglStopValue = toPropertyValue(stopValue);
- NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
- mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
- }];
- return mbgl::style::Function<MBGLType>({{mbglStops}}, function.interpolationBase);
+ return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value);
+ } else if ([value isMemberOfClass:[MGLStyleFunction class]]) {
+ MGLStyleFunction<ObjCType> *styleFunction = (MGLStyleFunction<ObjCType> *)value;
+ return toMBGLExponentialCameraFunction(styleFunction);
+ } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction<ObjCType> *cameraStyleFunction = (MGLCameraStyleFunction<ObjCType> *)value;
+ switch (cameraStyleFunction.interpolationMode) {
+ case MGLInterpolationModeExponential:
+ return toMBGLExponentialCameraFunction(cameraStyleFunction);
+ break;
+ case MGLInterpolationModeInterval:
+ return toMBGLIntervalCameraFunction(cameraStyleFunction);
+ break;
+ default:
+ [NSException raise:NSInvalidArgumentException
+ format:@"A camera function must use either exponential or interval stops."];
+ break;
+ }
+ return {};
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -73,25 +117,51 @@ public:
}
}
+ // Convert an mgl style value into a mbgl data driven property value
+ mbgl::style::DataDrivenPropertyValue<MBGLType> toDataDrivenPropertyValue(MGLStyleValue<ObjCType> *value) {
+ if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
+ return toMBGLConstantValue((MGLStyleConstantValue<ObjCType> *)value);
+ } else if ([value isKindOfClass:[MGLStyleFunction class]]) {
+ auto rawValue = toRawStyleSpecValue((MGLStyleFunction<ObjCType> *) value);
+ auto result = mbgl::style::conversion::convert<mbgl::style::DataDrivenPropertyValue<MBGLType>>(rawValue);
+ NSCAssert(result, @(result.error().message.c_str()));
+ return *result;
+ } else {
+ return {};
+ }
+ }
+
+ // Convert an mgl style value containing an enum into a mbgl property value containing an enum
template <typename MBGLEnum = MBGLType,
class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
typename MGLEnum = ObjCEnum,
class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
mbgl::style::PropertyValue<MBGLEnum> toEnumPropertyValue(MGLStyleValue<ObjCType> *value) {
+ if ([value isKindOfClass:[MGLSourceStyleFunction class]] || [value isKindOfClass:[MGLCompositeStyleFunction class]]) {
+ [NSException raise:NSInvalidArgumentException
+ format:@"This property can only be set to camera functions. Use +[MGLStyleValue cameraFunctionValueWithinterpolationMode:stops:options:] instead."];
+ return {};
+ }
+
if ([value isKindOfClass:[MGLStyleConstantValue class]]) {
MBGLEnum mbglValue;
getMBGLValue([(MGLStyleConstantValue<ObjCType> *)value rawValue], mbglValue);
return mbglValue;
- } else if ([value isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction<NSValue *> *function = (MGLStyleFunction<NSValue *> *)value;
- __block std::vector<std::pair<float, MBGLEnum>> mbglStops;
- [function.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<NSValue *> * _Nonnull stopValue, BOOL * _Nonnull stop) {
+ } else if ([value isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction<NSValue *> *cameraStyleFunction = (MGLCameraStyleFunction<NSValue *> *)value;
+ __block std::map<float, MBGLType> stops = {};
+ [cameraStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<NSValue *> * _Nonnull stopValue, BOOL * _Nonnull stop) {
NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
auto mbglStopValue = toEnumPropertyValue(stopValue);
NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
- mbglStops.emplace_back(zoomKey.floatValue, mbglStopValue.asConstant());
+ stops[zoomKey.floatValue] = mbglStopValue.asConstant();
}];
- return mbgl::style::Function<MBGLEnum>({{mbglStops}}, function.interpolationBase);
+
+ // Enumerations can only ever use interval stops.
+ mbgl::style::IntervalStops<MBGLType> intervalStops = {stops};
+
+ mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops};
+ return cameraFunction;
} else if (value) {
[NSException raise:@"MGLAbstractClassException" format:
@"The style value %@ cannot be applied to the style. "
@@ -103,95 +173,239 @@ public:
}
}
-private:
+private: // Private utilities for converting from mgl to mbgl values
- MGLStyleConstantValue<ObjCType> *toStyleConstantValue(const MBGLType mbglValue) {
- auto rawValue = toMGLRawStyleValue(mbglValue);
- return [MGLStyleConstantValue<ObjCType> valueWithRawValue:rawValue];
+ MBGLType toMBGLConstantValue(MGLStyleConstantValue<ObjCType> *value) {
+ MBGLType mbglValue;
+ getMBGLValue(value.rawValue, mbglValue);
+ return mbglValue;
}
- MGLStyleFunction<ObjCType> *toStyleFunction(const mbgl::style::Function<MBGLType> &mbglFunction) {
- const auto &mbglStops = mbglFunction.getStops();
- NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()];
- for (const auto &mbglStop : mbglStops) {
- auto rawValue = toMGLRawStyleValue(mbglStop.second);
- stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue];
+ /**
+ As hack to allow converting enum => string values, we accept a second, dummy parameter in
+ the toRawStyleSpecValue() methods for converting 'atomic' (non-style-function) values.
+ This allows us to use `std::enable_if` to test (at compile time) whether or not MBGLType is an Enum.
+ */
+ template <typename MBGLEnum = MBGLType,
+ class = typename std::enable_if<!std::is_enum<MBGLEnum>::value>::type,
+ typename MGLEnum = ObjCEnum,
+ class = typename std::enable_if<!std::is_enum<MGLEnum>::value>::type>
+ NSObject* toRawStyleSpecValue(NSObject *rawMGLValue, MBGLEnum &mbglValue) {
+ if ([rawMGLValue isKindOfClass:[NSValue class]]) {
+ const auto rawNSValue = (NSValue *)rawMGLValue;
+ if (strcmp([rawNSValue objCType], @encode(CGVector)) == 0) {
+ // offset [x, y]
+ std::array<float, 2> mglValue = rawNSValue.mgl_offsetArrayValue;
+ return [NSArray arrayWithObjects:@(mglValue[0]), @(mglValue[1]), nil];
+ }
}
- return [MGLStyleFunction<ObjCType> functionWithInterpolationBase:mbglFunction.getBase() stops:stops];
+ // noop pass-through plain NSObject-based items
+ return rawMGLValue;
}
-
+
template <typename MBGLEnum = MBGLType,
- class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
- typename MGLEnum = ObjCEnum,
- class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
- MGLStyleConstantValue<ObjCType> *toEnumStyleConstantValue(const MBGLEnum mbglValue) {
- auto str = mbgl::Enum<MBGLEnum>::toString(mbglValue);
- MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str);
- return [MGLStyleConstantValue<ObjCType> valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]];
- }
-
- NSNumber *toMGLRawStyleValue(const bool mbglStopValue) {
- return @(mbglStopValue);
+ class = typename std::enable_if<std::is_enum<MBGLEnum>::value>::type,
+ typename MGLEnum = ObjCEnum,
+ class = typename std::enable_if<std::is_enum<MGLEnum>::value>::type>
+ NSString* toRawStyleSpecValue(ObjCType rawValue, MBGLEnum &mbglValue) {
+ MGLEnum mglEnum;
+ [rawValue getValue:&mglEnum];
+ return @(mbgl::Enum<MGLEnum>::toString(mglEnum));
}
- NSNumber *toMGLRawStyleValue(const float mbglStopValue) {
- return @(mbglStopValue);
+ NSObject* toRawStyleSpecValue(MGLColor *color, MBGLType &mbglValue) {
+ return @(color.mgl_color.stringify().c_str());
}
+
- NSString *toMGLRawStyleValue(const std::string &mbglStopValue) {
- return @(mbglStopValue.c_str());
+ NSObject* toRawStyleSpecValue(MGLStyleFunction<ObjCType>* styleFunction) {
+ NSMutableDictionary * rawFunction = [NSMutableDictionary new];
+ // interpolationMode => type
+ switch (styleFunction.interpolationMode) {
+ case MGLInterpolationModeExponential:
+ rawFunction[@"type"] = @"exponential";
+ break;
+ case MGLInterpolationModeInterval:
+ rawFunction[@"type"] = @"interval";
+ break;
+ case MGLInterpolationModeCategorical:
+ rawFunction[@"type"] = @"categorical";
+ break;
+ case MGLInterpolationModeIdentity:
+ rawFunction[@"type"] = @"identity";
+ break;
+ }
+
+ // interpolationBase => base
+ if (styleFunction.interpolationBase) {
+ rawFunction[@"base"] = @(styleFunction.interpolationBase);
+ }
+
+ // stops and default value
+ if ([styleFunction isKindOfClass:[MGLCameraStyleFunction class]]) {
+ // zoom-only function (no default value)
+ __block NSMutableArray *stops = [[NSMutableArray alloc] init];
+ [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
+ MBGLType dummyMbglValue;
+ NSArray *rawStop = @[zoomKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
+ [stops addObject:rawStop];
+ }];
+ rawFunction[@"stops"] = stops;
+
+ } else if ([styleFunction isKindOfClass:[MGLSourceStyleFunction class]]) {
+ auto sourceStyleFunction = (MGLSourceStyleFunction<ObjCType> *)styleFunction;
+ rawFunction[@"property"] = sourceStyleFunction.attributeName;
+ // property-only function
+ __block NSMutableArray *stops = [[NSMutableArray alloc] init];
+ [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSObject * _Nonnull propertyKey, MGLStyleConstantValue<ObjCType> * _Nonnull outputValue, BOOL * _Nonnull stop) {
+ MBGLType dummyMbglValue;
+ NSArray *rawStop = @[propertyKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
+ [stops addObject:rawStop];
+ }];
+ rawFunction[@"stops"] = stops;
+
+ // defaultValue => default
+ if (sourceStyleFunction.defaultValue) {
+ NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
+ MBGLType dummyMbglValue;
+ rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue], dummyMbglValue);
+ }
+ } else if ([styleFunction isKindOfClass:[MGLCompositeStyleFunction class]]) {
+ // zoom-and-property function
+ auto compositeStyleFunction = (MGLCompositeStyleFunction<ObjCType> *)styleFunction;
+ rawFunction[@"property"] = compositeStyleFunction.attributeName;
+
+ __block NSMutableArray *stops = [[NSMutableArray alloc] init];
+ [compositeStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, NSDictionary * _Nonnull stopValue, BOOL * _Nonnull stop) {
+ for (NSObject *valueKey in stopValue.allKeys) {
+ NSDictionary *stopKey = @{
+ @"zoom": zoomKey,
+ @"value": valueKey
+ };
+ MGLStyleConstantValue<ObjCType> *outputValue = stopValue[valueKey];
+ NSCAssert([outputValue isKindOfClass:[MGLStyleConstantValue<ObjCType> class]], @"Stop outputs should be MGLStyleConstantValues");
+ MBGLType dummyMbglValue;
+ NSArray *rawStop = @[stopKey, toRawStyleSpecValue([outputValue rawValue], dummyMbglValue)];
+ [stops addObject:rawStop];
+ }
+ }];
+ rawFunction[@"stops"] = stops;
+
+ // defaultValue => default
+ if (compositeStyleFunction.defaultValue) {
+ NSCAssert([compositeStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
+ MBGLType dummyMbglValue;
+ rawFunction[@"default"] = toRawStyleSpecValue([(MGLStyleConstantValue<ObjCType> *)compositeStyleFunction.defaultValue rawValue], dummyMbglValue);
+ }
+ }
+
+ return rawFunction;
}
-
- // Offsets
- NSValue *toMGLRawStyleValue(const std::array<float, 2> &mbglStopValue) {
- return [NSValue mgl_valueWithOffsetArray:mbglStopValue];
+
+ mbgl::style::CameraFunction<MBGLType> toMBGLExponentialCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
+ __block std::map<float, MBGLType> stops = {};
+ [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
+ NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
+ auto mbglStopValue = toPropertyValue(stopValue);
+ NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
+ stops[zoomKey.floatValue] = mbglStopValue.asConstant();
+ }];
+
+ // Camera function with Exponential stops
+ mbgl::style::ExponentialStops<MBGLType> exponentialStops = {stops, (float)styleFunction.interpolationBase};
+ mbgl::style::CameraFunction<MBGLType> cameraFunction = {exponentialStops};
+
+ return cameraFunction;
}
-
- // Padding
- NSValue *toMGLRawStyleValue(const std::array<float, 4> &mbglStopValue) {
- return [NSValue mgl_valueWithPaddingArray:mbglStopValue];
+
+ mbgl::style::CameraFunction<MBGLType> toMBGLIntervalCameraFunction(MGLStyleFunction<ObjCType> *styleFunction) {
+ __block std::map<float, MBGLType> stops = {};
+ [styleFunction.stops enumerateKeysAndObjectsUsingBlock:^(NSNumber * _Nonnull zoomKey, MGLStyleValue<ObjCType> * _Nonnull stopValue, BOOL * _Nonnull stop) {
+ NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
+ auto mbglStopValue = toPropertyValue(stopValue);
+ NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
+ stops[zoomKey.floatValue] = mbglStopValue.asConstant();
+ }];
+
+ // Camera function with Interval stops
+ mbgl::style::IntervalStops<MBGLType> intervalStops = {stops};
+ mbgl::style::CameraFunction<MBGLType> cameraFunction = {intervalStops};
+
+ return cameraFunction;
}
-
- MGLColor *toMGLRawStyleValue(const mbgl::Color mbglStopValue) {
- return [MGLColor mgl_colorWithColor:mbglStopValue];
+
+ mbgl::style::SourceFunction<MBGLType> toMBGLCategoricalSourceFunction(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction) {
+ __block std::map<mbgl::style::CategoricalValue, MBGLType> stops = {};
+ [sourceStyleFunction.stops enumerateKeysAndObjectsUsingBlock:^(id categoryKey, MGLStyleValue<ObjCType> *stopValue, BOOL *stop) {
+ NSCAssert([stopValue isKindOfClass:[MGLStyleValue class]], @"Stops should be MGLStyleValues");
+ auto mbglStopValue = toPropertyValue(stopValue);
+ NSCAssert(mbglStopValue.isConstant(), @"Stops must be constant");
+
+ if ([categoryKey isKindOfClass:[NSString class]]) {
+ const std::string& convertedValueKey = [((NSString *)categoryKey) UTF8String];
+ stops[mbgl::style::CategoricalValue(convertedValueKey)] = mbglStopValue.asConstant();
+ } else if ([categoryKey isKindOfClass:[NSNumber class]]) {
+ NSNumber *key = (NSNumber *)categoryKey;
+ if ((strcmp([key objCType], @encode(char)) == 0) ||
+ (strcmp([key objCType], @encode(BOOL)) == 0)) {
+ stops[mbgl::style::CategoricalValue((bool)[key boolValue])] = mbglStopValue.asConstant();
+ } else if (strcmp([key objCType], @encode(double)) == 0 ||
+ strcmp([key objCType], @encode(float)) == 0) {
+ NSCAssert(mbglStopValue.isConstant(), @"Categorical stop keys must be strings, booleans, or integers");
+ } else if ([key compare:@(0)] == NSOrderedDescending ||
+ [key compare:@(0)] == NSOrderedSame ||
+ [key compare:@(0)] == NSOrderedAscending) {
+ stops[mbgl::style::CategoricalValue((int64_t)[key integerValue])] = mbglStopValue.asConstant();
+ }
+ }
+ }];
+ mbgl::style::CategoricalStops<MBGLType> categoricalStops = {stops};
+ mbgl::style::SourceFunction<MBGLType> sourceFunction = {sourceStyleFunction.attributeName.UTF8String, categoricalStops};
+ setDefaultMBGLValue(sourceStyleFunction, sourceFunction);
+ return sourceFunction;
}
-
- ObjCType toMGLRawStyleValue(const std::vector<MBGLElement> &mbglStopValue) {
- NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()];
- for (const auto &mbglElement: mbglStopValue) {
- [array addObject:toMGLRawStyleValue(mbglElement)];
+
+ void setDefaultMBGLValue(MGLSourceStyleFunction<ObjCType> *sourceStyleFunction, mbgl::style::SourceFunction<MBGLType> &sourceFunction) {
+ if (sourceStyleFunction.defaultValue) {
+ NSCAssert([sourceStyleFunction.defaultValue isKindOfClass:[MGLStyleConstantValue class]], @"Default value must be constant");
+ MBGLType mbglValue;
+ id mglValue = [(MGLStyleConstantValue<ObjCType> *)sourceStyleFunction.defaultValue rawValue];
+ getMBGLValue(mglValue, mbglValue);
+ sourceFunction.defaultValue = mbglValue;
}
- return array;
}
-private:
-
+ // Bool
void getMBGLValue(NSNumber *rawValue, bool &mbglValue) {
mbglValue = !!rawValue.boolValue;
}
-
+
+ // Float
void getMBGLValue(NSNumber *rawValue, float &mbglValue) {
mbglValue = rawValue.floatValue;
}
-
+
+ // String
void getMBGLValue(NSString *rawValue, std::string &mbglValue) {
mbglValue = rawValue.UTF8String;
}
-
+
// Offsets
void getMBGLValue(NSValue *rawValue, std::array<float, 2> &mbglValue) {
mbglValue = rawValue.mgl_offsetArrayValue;
}
-
+
// Padding
void getMBGLValue(NSValue *rawValue, std::array<float, 4> &mbglValue) {
mbglValue = rawValue.mgl_paddingArrayValue;
}
-
+
+ // Color
void getMBGLValue(MGLColor *rawValue, mbgl::Color &mbglValue) {
mbglValue = rawValue.mgl_color;
}
-
+
+ // Array
void getMBGLValue(ObjCType rawValue, std::vector<MBGLElement> &mbglValue) {
mbglValue.reserve(rawValue.count);
for (id obj in rawValue) {
@@ -212,4 +426,267 @@ private:
auto str = mbgl::Enum<MGLEnum>::toString(mglEnum);
mbglValue = *mbgl::Enum<MBGLEnum>::toEnum(str);
}
+
+private: // Private utilities for converting from mbgl to mgl values
+
+ // Bool
+ static NSNumber *toMGLRawStyleValue(const bool mbglStopValue) {
+ return @(mbglStopValue);
+ }
+
+ // Float
+ static NSNumber *toMGLRawStyleValue(const float mbglStopValue) {
+ return @(mbglStopValue);
+ }
+
+ // Integer
+ static NSNumber *toMGLRawStyleValue(const int64_t mbglStopValue) {
+ return @(mbglStopValue);
+ }
+
+ // String
+ static NSString *toMGLRawStyleValue(const std::string &mbglStopValue) {
+ return @(mbglStopValue.c_str());
+ }
+
+ // Offsets
+ static NSValue *toMGLRawStyleValue(const std::array<float, 2> &mbglStopValue) {
+ return [NSValue mgl_valueWithOffsetArray:mbglStopValue];
+ }
+
+ // Padding
+ static NSValue *toMGLRawStyleValue(const std::array<float, 4> &mbglStopValue) {
+ return [NSValue mgl_valueWithPaddingArray:mbglStopValue];
+ }
+
+ // Color
+ static MGLColor *toMGLRawStyleValue(const mbgl::Color mbglStopValue) {
+ return [MGLColor mgl_colorWithColor:mbglStopValue];
+ }
+
+ // Array
+ static ObjCType toMGLRawStyleValue(const std::vector<MBGLElement> &mbglStopValue) {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:mbglStopValue.size()];
+ for (const auto &mbglElement: mbglStopValue) {
+ [array addObject:toMGLRawStyleValue(mbglElement)];
+ }
+ return array;
+ }
+
+ // Enumerations
+ template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
+ static NSValue *toMGLRawStyleValue(const MBGLEnum &value) {
+ auto str = mbgl::Enum<MBGLEnum>::toString(value);
+ MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str);
+ return [NSValue value:&mglType withObjCType:@encode(MGLEnum)];
+ }
+
+ // Converts mbgl stops to an equivilent NSDictionary for mgl
+ static NSMutableDictionary *toConvertedStops(const std::map<float, MBGLType> &mbglStops) {
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.size()];
+ for (const auto &mbglStop : mbglStops) {
+ auto rawValue = toMGLRawStyleValue(mbglStop.second);
+ stops[@(mbglStop.first)] = [MGLStyleValue valueWithRawValue:rawValue];
+ }
+ return stops;
+ }
+
+ // Converts mbgl interval stop categorical values to an equivilant object for mgl
+ class CategoricalValueVisitor {
+ public:
+ id operator()(const bool value) {
+ return toMGLRawStyleValue(value);
+ }
+
+ id operator()(const int64_t value) {
+ return toMGLRawStyleValue(value);
+ }
+
+ id operator()(const std::string value) {
+ return toMGLRawStyleValue(value);
+ }
+ };
+
+ // Converts all types of mbgl property values containing enumerations into an equivilant mgl style value
+ template <typename MBGLEnum = MBGLType, typename MGLEnum = ObjCEnum>
+ class EnumPropertyValueEvaluator {
+ public:
+ id operator()(const mbgl::style::Undefined) const {
+ return nil;
+ }
+
+ id operator()(const MBGLEnum &value) const {
+ auto str = mbgl::Enum<MBGLEnum>::toString(value);
+ MGLEnum mglType = *mbgl::Enum<MGLEnum>::toEnum(str);
+ return [MGLStyleConstantValue<ObjCType> valueWithRawValue:[NSValue value:&mglType withObjCType:@encode(MGLEnum)]];
+ }
+
+ id operator()(const mbgl::style::CameraFunction<MBGLEnum> &mbglValue) const {
+ CameraFunctionStopsVisitor visitor;
+ return apply_visitor(visitor, mbglValue.stops);
+ }
+ };
+
+ // Converts all possible mbgl camera function stops into an equivilant mgl style value
+ class CameraFunctionStopsVisitor {
+ public:
+ id operator()(const mbgl::style::ExponentialStops<MBGLType> &mbglStops) {
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
+ stops:toConvertedStops(mbglStops.stops)
+ options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
+ }
+
+ id operator()(const mbgl::style::IntervalStops<MBGLType> &mbglStops) {
+ return [MGLCameraStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
+ stops:toConvertedStops(mbglStops.stops)
+ options:nil];
+ }
+ };
+
+ // Converts a source function and all possible mbgl source function stops into an equivilant mgl style value
+ class SourceFunctionStopsVisitor {
+ public:
+ id operator()(const mbgl::style::ExponentialStops<MBGLType> &mbglStops) {
+ MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
+ stops:toConvertedStops(mbglStops.stops)
+ attributeName:@(mbglFunction.property.c_str())
+ options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
+ if (mbglFunction.defaultValue) {
+ sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return sourceFunction;
+ }
+
+ id operator()(const mbgl::style::IntervalStops<MBGLType> &mbglStops) {
+ MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
+ stops:toConvertedStops(mbglStops.stops)
+ attributeName:@(mbglFunction.property.c_str())
+ options:nil];
+ if (mbglFunction.defaultValue) {
+ sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return sourceFunction;
+ }
+
+ id operator()(const mbgl::style::CategoricalStops<MBGLType> &mbglStops) {
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
+ for (const auto &mbglStop : mbglStops.stops) {
+ auto categoricalValue = mbglStop.first;
+ auto rawValue = toMGLRawStyleValue(mbglStop.second);
+ CategoricalValueVisitor categoricalValueVisitor;
+ id stopKey = apply_visitor(categoricalValueVisitor, categoricalValue);
+ stops[stopKey] = [MGLStyleValue valueWithRawValue:rawValue];
+ }
+
+ MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeCategorical
+ stops:stops
+ attributeName:@(mbglFunction.property.c_str())
+ options:nil];
+ if (mbglFunction.defaultValue) {
+ sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return sourceFunction;
+
+ }
+
+ id operator()(const mbgl::style::IdentityStops<MBGLType> &mbglStops) {
+ MGLSourceStyleFunction *sourceFunction = [MGLSourceStyleFunction functionWithInterpolationMode:MGLInterpolationModeIdentity
+ stops:nil
+ attributeName:@(mbglFunction.property.c_str()) options:nil];
+ if (mbglFunction.defaultValue) {
+ sourceFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return sourceFunction;
+ }
+
+ const mbgl::style::SourceFunction<MBGLType> &mbglFunction;
+ };
+
+ // Converts a composite function and all possible mbgl stops into an equivilant mgl style value
+ class CompositeFunctionStopsVisitor {
+ public:
+ id operator()(const mbgl::style::CompositeExponentialStops<MBGLType> &mbglStops) {
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
+ for (auto const& outerStop: mbglStops.stops) {
+ stops[@(outerStop.first)] = toConvertedStops(outerStop.second);
+ }
+ MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeExponential
+ stops:stops
+ attributeName:@(mbglFunction.property.c_str())
+ options:@{MGLStyleFunctionOptionInterpolationBase: @(mbglStops.base)}];
+ if (mbglFunction.defaultValue) {
+ compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return compositeFunction;
+ }
+
+ id operator()(const mbgl::style::CompositeIntervalStops<MBGLType> &mbglStops) {
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
+ for (auto const& outerStop: mbglStops.stops) {
+ stops[@(outerStop.first)] = toConvertedStops(outerStop.second);
+ }
+ MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeInterval
+ stops:stops
+ attributeName:@(mbglFunction.property.c_str())
+ options:nil];
+ if (mbglFunction.defaultValue) {
+ compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return compositeFunction;
+ }
+
+ id operator()(const mbgl::style::CompositeCategoricalStops<MBGLType> &mbglStops) {
+ NSMutableDictionary *stops = [NSMutableDictionary dictionaryWithCapacity:mbglStops.stops.size()];
+ for (auto const& outerStop: mbglStops.stops) {
+ NSMutableDictionary *innerStops = [NSMutableDictionary dictionaryWithCapacity:outerStop.second.size()];
+ for (const auto &mbglStop : outerStop.second) {
+ auto categoricalValue = mbglStop.first;
+ auto rawValue = toMGLRawStyleValue(mbglStop.second);
+ CategoricalValueVisitor categoricalValueVisitor;
+ id stopKey = apply_visitor(categoricalValueVisitor, categoricalValue);
+ innerStops[stopKey] = [MGLStyleValue valueWithRawValue:rawValue];
+ }
+ stops[@(outerStop.first)] = innerStops;
+ }
+
+ MGLCompositeStyleFunction *compositeFunction = [MGLCompositeStyleFunction functionWithInterpolationMode:MGLInterpolationModeCategorical
+ stops:stops attributeName:@(mbglFunction.property.c_str())
+ options:nil];
+ if (mbglFunction.defaultValue) {
+ compositeFunction.defaultValue = [MGLStyleValue valueWithRawValue:toMGLRawStyleValue(*mbglFunction.defaultValue)];
+ }
+ return compositeFunction;
+ }
+
+ const mbgl::style::CompositeFunction<MBGLType> &mbglFunction;
+ };
+
+
+ // Converts all types of mbgl property values that don't contain enumerations into an equivilant mgl style value
+ class PropertyValueEvaluator {
+ public:
+ id operator()(const mbgl::style::Undefined) const {
+ return nil;
+ }
+
+ id operator()(const MBGLType &value) const {
+ auto rawValue = toMGLRawStyleValue(value);
+ return [MGLStyleConstantValue<ObjCType> valueWithRawValue:rawValue];
+ }
+
+ id operator()(const mbgl::style::CameraFunction<MBGLType> &mbglValue) const {
+ CameraFunctionStopsVisitor visitor;
+ return apply_visitor(visitor, mbglValue.stops);
+ }
+
+ id operator()(const mbgl::style::SourceFunction<MBGLType> &mbglValue) const {
+ SourceFunctionStopsVisitor visitor { mbglValue };
+ return apply_visitor(visitor, mbglValue.stops);
+ }
+
+ MGLCompositeStyleFunction<ObjCType> * operator()(const mbgl::style::CompositeFunction<MBGLType> &mbglValue) const {
+ CompositeFunctionStopsVisitor visitor { mbglValue };
+ return apply_visitor(visitor, mbglValue.stops);
+ }
+ };
};
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index 23ddd59d0d..a4850a4e18 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
#import "MGLFoundation.h"
@@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
In combination with `symbolPlacement`, determines the rotation behavior of
icons.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.iconRotationAlignment`
property.
*/
@@ -37,7 +37,7 @@ typedef NS_ENUM(NSUInteger, MGLIconRotationAlignment) {
/**
Scales the icon to fit around the associated text.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.iconTextFit`
property.
*/
@@ -62,7 +62,7 @@ typedef NS_ENUM(NSUInteger, MGLIconTextFit) {
/**
Label placement relative to its geometry.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.symbolPlacement`
property.
*/
@@ -80,7 +80,7 @@ typedef NS_ENUM(NSUInteger, MGLSymbolPlacement) {
/**
Part of the text placed closest to the anchor.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textAnchor`
property.
*/
@@ -125,7 +125,7 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) {
/**
Text justification options.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textJustification`
property.
*/
@@ -146,7 +146,7 @@ typedef NS_ENUM(NSUInteger, MGLTextJustification) {
/**
Orientation of text when map is pitched.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textPitchAlignment`
property.
*/
@@ -168,7 +168,7 @@ typedef NS_ENUM(NSUInteger, MGLTextPitchAlignment) {
/**
In combination with `symbolPlacement`, determines the rotation behavior of the
individual glyphs forming the text.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textRotationAlignment`
property.
*/
@@ -195,7 +195,7 @@ typedef NS_ENUM(NSUInteger, MGLTextRotationAlignment) {
/**
Specifies how to capitalize text.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textTransform`
property.
*/
@@ -216,7 +216,7 @@ typedef NS_ENUM(NSUInteger, MGLTextTransform) {
/**
Controls the translation reference point.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.iconTranslationAnchor`
property.
*/
@@ -233,7 +233,7 @@ typedef NS_ENUM(NSUInteger, MGLIconTranslationAnchor) {
/**
Controls the translation reference point.
-
+
Values of this type are used in the `MGLSymbolStyleLayer.textTranslationAnchor`
property.
*/
@@ -255,15 +255,15 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
Use a symbol style layer to configure the visual appearance of labels for
features in vector tiles loaded by an `MGLVectorSource` object or `MGLShape` or
`MGLFeature` instances in an `MGLShapeSource` object.
-
+
You can access an existing symbol style layer using the
`-[MGLStyle layerWithIdentifier:]` method if you know its identifier;
otherwise, find it using the `MGLStyle.layers` property. You can also create a
new symbol style layer and add it to the style using a method such as
`-[MGLStyle addLayer:]`.
-
+
### Example
-
+
```swift
let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
layer.sourceLayerIdentifier = "pois"
@@ -296,6 +296,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-allow-overlap"><code>icon-allow-overlap</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconAllowsOverlap;
@@ -315,6 +321,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-ignore-placement"><code>icon-ignore-placement</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconIgnoresPlacement;
@@ -327,6 +339,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-image"><code>icon-image</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *iconImageName;
@@ -343,6 +361,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
#else
@@ -355,6 +389,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconOffset;
#endif
@@ -369,6 +419,12 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`, and
`text` is non-`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable, getter=isIconOptional) MGLStyleValue<NSNumber *> *iconOptional;
@@ -384,6 +440,13 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconPadding;
@@ -402,6 +465,22 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-rotate"><code>icon-rotate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconRotation;
@@ -418,6 +497,12 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
@@ -434,6 +519,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-size"><code>icon-size</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconScale;
@@ -449,6 +541,12 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`, and
`text` is non-`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFit;
@@ -466,6 +564,13 @@ MGL_EXPORT
`text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
containing an `NSValue` object containing `MGLIconTextFitBoth`,
`MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
#else
@@ -482,6 +587,13 @@ MGL_EXPORT
`text` is non-`nil`, and `iconTextFit` is set to an `MGLStyleValue` object
containing an `NSValue` object containing `MGLIconTextFitBoth`,
`MGLIconTextFitWidth`, or `MGLIconTextFitHeight`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTextFitPadding;
#endif
@@ -502,6 +614,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-icon-keep-upright"><code>icon-keep-upright</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsIconUpright;
@@ -525,6 +643,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-keep-upright"><code>text-keep-upright</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *keepsTextUpright;
@@ -547,6 +671,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-angle"><code>text-max-angle</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextAngle;
@@ -568,6 +699,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-max-width"><code>text-max-width</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *maximumTextWidth;
@@ -587,6 +725,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-symbol-avoid-edges"><code>symbol-avoid-edges</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolAvoidsEdges;
@@ -599,6 +743,12 @@ MGL_EXPORT
The default value of this property is an `MGLStyleValue` object containing an
`NSValue` object containing `MGLSymbolPlacementPoint`. Set this property to
`nil` to reset it to the default value.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *symbolPlacement;
@@ -614,12 +764,20 @@ MGL_EXPORT
This property is only applied to the style if `symbolPlacement` is set to an
`MGLStyleValue` object containing an `NSValue` object containing
`MGLSymbolPlacementLine`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *symbolSpacing;
/**
Value to use for a text label. Feature properties are specified using tokens
- like {field_name}.
+ like {field_name}. (Token replacement is only supported for literal
+ `textField` values--not for property functions.)
The default value of this property is an `MGLStyleValue` object containing the
empty string. Set this property to `nil` to reset it to the default value.
@@ -627,6 +785,22 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-field"><code>text-field</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSString *> *text;
@@ -647,6 +821,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-allow-overlap"><code>text-allow-overlap</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textAllowsOverlap;
@@ -662,6 +842,12 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textAnchor;
@@ -688,6 +874,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-font"><code>text-font</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSArray<NSString *> *> *textFontNames;
@@ -709,6 +901,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-size"><code>text-size</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textFontSize;
@@ -728,6 +927,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-ignore-placement"><code>text-ignore-placement</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textIgnoresPlacement;
@@ -747,6 +952,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-justify"><code>text-justify</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textJustification;
@@ -764,6 +975,13 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLetterSpacing;
@@ -778,6 +996,13 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textLineHeight;
@@ -793,6 +1018,13 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
#else
@@ -807,6 +1039,13 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textOffset;
#endif
@@ -821,6 +1060,12 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`, and
`iconImageName` is non-`nil`. Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable, getter=isTextOptional) MGLStyleValue<NSNumber *> *textOptional;
@@ -836,6 +1081,13 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textPadding;
@@ -848,6 +1100,12 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textPitchAlignment;
@@ -866,6 +1124,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#layout-symbol-text-rotate"><code>text-rotate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textRotation;
@@ -882,6 +1147,12 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textRotationAlignment;
@@ -894,6 +1165,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTransform;
@@ -910,6 +1197,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconColor;
#else
@@ -923,6 +1226,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconColor;
#endif
@@ -938,6 +1257,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloBlur;
@@ -952,6 +1287,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *iconHaloColor;
#else
@@ -965,6 +1316,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *iconHaloColor;
#endif
@@ -980,6 +1347,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconHaloWidth;
@@ -992,6 +1375,22 @@ MGL_EXPORT
This property is only applied to the style if `iconImageName` is non-`nil`.
Otherwise, it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *iconOpacity;
@@ -1011,6 +1410,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslation;
#else
@@ -1029,6 +1435,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate"><code>icon-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslation;
#endif
@@ -1048,6 +1461,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-icon-translate-anchor"><code>icon-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconTranslationAnchor;
@@ -1063,6 +1482,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textColor;
#else
@@ -1075,6 +1510,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textColor;
#endif
@@ -1090,6 +1541,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloBlur;
@@ -1103,6 +1570,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<UIColor *> *textHaloColor;
#else
@@ -1115,6 +1598,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSColor *> *textHaloColor;
#endif
@@ -1131,6 +1630,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textHaloWidth;
@@ -1143,6 +1658,22 @@ MGL_EXPORT
This property is only applied to the style if `text` is non-`nil`. Otherwise,
it is ignored.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *textOpacity;
@@ -1162,6 +1693,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslation;
#else
@@ -1180,6 +1718,13 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate"><code>text-translate</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslation;
#endif
@@ -1199,6 +1744,12 @@ MGL_EXPORT
This attribute corresponds to the <a
href="https://www.mapbox.com/mapbox-gl-style-spec/#paint-text-translate-anchor"><code>text-translate-anchor</code></a>
layout property in the Mapbox Style Specification.
+
+ You can set this property to an instance of:
+
+ * `MGLStyleConstantValue`
+ * `MGLCameraStyleFunction` with an interpolation mode of
+ `MGLInterpolationModeInterval`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *textTranslationAnchor;
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm
index 493a8c5b6f..52648e7a05 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.mm
+++ b/platform/darwin/src/MGLSymbolStyleLayer.mm
@@ -1,4 +1,4 @@
-// This file is generated.
+// This file is generated.
// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLSource.h"
@@ -113,7 +113,7 @@ namespace mbgl {
- (NSString *)sourceIdentifier
{
MGLAssertStyleLayerIsValid();
-
+
return @(self.rawLayer->getSourceID().c_str());
}
@@ -166,8 +166,9 @@ namespace mbgl {
- (void)removeFromMapView:(MGLMapView *)mapView
{
- _pendingLayer = nullptr;
- self.rawLayer = nullptr;
+ if (self.rawLayer != mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
+ return;
+ }
auto removedLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
if (!removedLayer) {
@@ -197,7 +198,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)iconAllowsOverlap {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconAllowOverlap() ?: self.rawLayer->getDefaultIconAllowOverlap();
+ auto propertyValue = self.rawLayer->getIconAllowOverlap();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconAllowOverlap());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -218,7 +222,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)iconIgnoresPlacement {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconIgnorePlacement() ?: self.rawLayer->getDefaultIconIgnorePlacement();
+ auto propertyValue = self.rawLayer->getIconIgnorePlacement();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconIgnorePlacement());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -239,7 +246,10 @@ namespace mbgl {
- (MGLStyleValue<NSString *> *)iconImageName {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconImage() ?: self.rawLayer->getDefaultIconImage();
+ auto propertyValue = self.rawLayer->getIconImage();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(self.rawLayer->getDefaultIconImage());
+ }
return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
}
@@ -253,15 +263,18 @@ namespace mbgl {
- (void)setIconOffset:(MGLStyleValue<NSValue *> *)iconOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconOffset);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenPropertyValue(iconOffset);
self.rawLayer->setIconOffset(mbglValue);
}
- (MGLStyleValue<NSValue *> *)iconOffset {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconOffset() ?: self.rawLayer->getDefaultIconOffset();
- return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconOffset();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOffset());
+ }
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconOptional:(MGLStyleValue<NSNumber *> *)iconOptional {
@@ -274,36 +287,45 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)isIconOptional {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconOptional() ?: self.rawLayer->getDefaultIconOptional();
+ auto propertyValue = self.rawLayer->getIconOptional();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconOptional());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconPadding:(MGLStyleValue<NSNumber *> *)iconPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconPadding);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconPadding);
self.rawLayer->setIconPadding(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconPadding {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconPadding() ?: self.rawLayer->getDefaultIconPadding();
+ auto propertyValue = self.rawLayer->getIconPadding();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconPadding());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setIconRotation:(MGLStyleValue<NSNumber *> *)iconRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconRotation);
self.rawLayer->setIconRotate(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconRotation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconRotate() ?: self.rawLayer->getDefaultIconRotate();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconRotate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconRotate());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconRotate:(MGLStyleValue<NSNumber *> *)iconRotate {
@@ -323,21 +345,27 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)iconRotationAlignment {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconRotationAlignment() ?: self.rawLayer->getDefaultIconRotationAlignment();
+ auto propertyValue = self.rawLayer->getIconRotationAlignment();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumStyleValue(self.rawLayer->getDefaultIconRotationAlignment());
+ }
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLIconRotationAlignment>().toEnumStyleValue(propertyValue);
}
- (void)setIconScale:(MGLStyleValue<NSNumber *> *)iconScale {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconScale);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(iconScale);
self.rawLayer->setIconSize(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconScale {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconSize() ?: self.rawLayer->getDefaultIconSize();
+ auto propertyValue = self.rawLayer->getIconSize();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconSize());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -358,21 +386,27 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)iconTextFit {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconTextFit() ?: self.rawLayer->getDefaultIconTextFit();
+ auto propertyValue = self.rawLayer->getIconTextFit();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumStyleValue(self.rawLayer->getDefaultIconTextFit());
+ }
return MGLStyleValueTransformer<mbgl::style::IconTextFitType, NSValue *, mbgl::style::IconTextFitType, MGLIconTextFit>().toEnumStyleValue(propertyValue);
}
- (void)setIconTextFitPadding:(MGLStyleValue<NSValue *> *)iconTextFitPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toPropertyValue(iconTextFitPadding);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toInterpolatablePropertyValue(iconTextFitPadding);
self.rawLayer->setIconTextFitPadding(mbglValue);
}
- (MGLStyleValue<NSValue *> *)iconTextFitPadding {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconTextFitPadding() ?: self.rawLayer->getDefaultIconTextFitPadding();
+ auto propertyValue = self.rawLayer->getIconTextFitPadding();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTextFitPadding());
+ }
return MGLStyleValueTransformer<std::array<float, 4>, NSValue *>().toStyleValue(propertyValue);
}
@@ -386,7 +420,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)keepsIconUpright {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconKeepUpright() ?: self.rawLayer->getDefaultIconKeepUpright();
+ auto propertyValue = self.rawLayer->getIconKeepUpright();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultIconKeepUpright());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -407,7 +444,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)keepsTextUpright {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextKeepUpright() ?: self.rawLayer->getDefaultTextKeepUpright();
+ auto propertyValue = self.rawLayer->getTextKeepUpright();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextKeepUpright());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -421,14 +461,17 @@ namespace mbgl {
- (void)setMaximumTextAngle:(MGLStyleValue<NSNumber *> *)maximumTextAngle {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumTextAngle);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumTextAngle);
self.rawLayer->setTextMaxAngle(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)maximumTextAngle {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextMaxAngle() ?: self.rawLayer->getDefaultTextMaxAngle();
+ auto propertyValue = self.rawLayer->getTextMaxAngle();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextMaxAngle());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -442,14 +485,17 @@ namespace mbgl {
- (void)setMaximumTextWidth:(MGLStyleValue<NSNumber *> *)maximumTextWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(maximumTextWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(maximumTextWidth);
self.rawLayer->setTextMaxWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)maximumTextWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextMaxWidth() ?: self.rawLayer->getDefaultTextMaxWidth();
+ auto propertyValue = self.rawLayer->getTextMaxWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextMaxWidth());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -470,7 +516,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)symbolAvoidsEdges {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getSymbolAvoidEdges() ?: self.rawLayer->getDefaultSymbolAvoidEdges();
+ auto propertyValue = self.rawLayer->getSymbolAvoidEdges();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultSymbolAvoidEdges());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -491,36 +540,45 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)symbolPlacement {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getSymbolPlacement() ?: self.rawLayer->getDefaultSymbolPlacement();
+ auto propertyValue = self.rawLayer->getSymbolPlacement();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumStyleValue(self.rawLayer->getDefaultSymbolPlacement());
+ }
return MGLStyleValueTransformer<mbgl::style::SymbolPlacementType, NSValue *, mbgl::style::SymbolPlacementType, MGLSymbolPlacement>().toEnumStyleValue(propertyValue);
}
- (void)setSymbolSpacing:(MGLStyleValue<NSNumber *> *)symbolSpacing {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(symbolSpacing);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(symbolSpacing);
self.rawLayer->setSymbolSpacing(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)symbolSpacing {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getSymbolSpacing() ?: self.rawLayer->getDefaultSymbolSpacing();
+ auto propertyValue = self.rawLayer->getSymbolSpacing();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultSymbolSpacing());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setText:(MGLStyleValue<NSString *> *)text {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toPropertyValue(text);
+ auto mbglValue = MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenPropertyValue(text);
self.rawLayer->setTextField(mbglValue);
}
- (MGLStyleValue<NSString *> *)text {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextField() ?: self.rawLayer->getDefaultTextField();
- return MGLStyleValueTransformer<std::string, NSString *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextField();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextField());
+ }
+ return MGLStyleValueTransformer<std::string, NSString *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextField:(MGLStyleValue<NSString *> *)textField {
@@ -540,7 +598,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)textAllowsOverlap {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextAllowOverlap() ?: self.rawLayer->getDefaultTextAllowOverlap();
+ auto propertyValue = self.rawLayer->getTextAllowOverlap();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextAllowOverlap());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -561,7 +622,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)textAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextAnchor() ?: self.rawLayer->getDefaultTextAnchor();
+ auto propertyValue = self.rawLayer->getTextAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(self.rawLayer->getDefaultTextAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TextAnchorType, NSValue *, mbgl::style::TextAnchorType, MGLTextAnchor>().toEnumStyleValue(propertyValue);
}
@@ -575,7 +639,10 @@ namespace mbgl {
- (MGLStyleValue<NSArray<NSString *> *> *)textFontNames {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextFont() ?: self.rawLayer->getDefaultTextFont();
+ auto propertyValue = self.rawLayer->getTextFont();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(self.rawLayer->getDefaultTextFont());
+ }
return MGLStyleValueTransformer<std::vector<std::string>, NSArray<NSString *> *, std::string>().toStyleValue(propertyValue);
}
@@ -589,14 +656,17 @@ namespace mbgl {
- (void)setTextFontSize:(MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textFontSize);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textFontSize);
self.rawLayer->setTextSize(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textFontSize {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextSize() ?: self.rawLayer->getDefaultTextSize();
+ auto propertyValue = self.rawLayer->getTextSize();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextSize());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -617,7 +687,10 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)textIgnoresPlacement {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextIgnorePlacement() ?: self.rawLayer->getDefaultTextIgnorePlacement();
+ auto propertyValue = self.rawLayer->getTextIgnorePlacement();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextIgnorePlacement());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
@@ -638,7 +711,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)textJustification {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextJustify() ?: self.rawLayer->getDefaultTextJustify();
+ auto propertyValue = self.rawLayer->getTextJustify();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(self.rawLayer->getDefaultTextJustify());
+ }
return MGLStyleValueTransformer<mbgl::style::TextJustifyType, NSValue *, mbgl::style::TextJustifyType, MGLTextJustification>().toEnumStyleValue(propertyValue);
}
@@ -652,42 +728,51 @@ namespace mbgl {
- (void)setTextLetterSpacing:(MGLStyleValue<NSNumber *> *)textLetterSpacing {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textLetterSpacing);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textLetterSpacing);
self.rawLayer->setTextLetterSpacing(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textLetterSpacing {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextLetterSpacing() ?: self.rawLayer->getDefaultTextLetterSpacing();
+ auto propertyValue = self.rawLayer->getTextLetterSpacing();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextLetterSpacing());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextLineHeight:(MGLStyleValue<NSNumber *> *)textLineHeight {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textLineHeight);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textLineHeight);
self.rawLayer->setTextLineHeight(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textLineHeight {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextLineHeight() ?: self.rawLayer->getDefaultTextLineHeight();
+ auto propertyValue = self.rawLayer->getTextLineHeight();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextLineHeight());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextOffset:(MGLStyleValue<NSValue *> *)textOffset {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textOffset);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(textOffset);
self.rawLayer->setTextOffset(mbglValue);
}
- (MGLStyleValue<NSValue *> *)textOffset {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextOffset() ?: self.rawLayer->getDefaultTextOffset();
+ auto propertyValue = self.rawLayer->getTextOffset();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextOffset());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -701,21 +786,27 @@ namespace mbgl {
- (MGLStyleValue<NSNumber *> *)isTextOptional {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextOptional() ?: self.rawLayer->getDefaultTextOptional();
+ auto propertyValue = self.rawLayer->getTextOptional();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextOptional());
+ }
return MGLStyleValueTransformer<bool, NSNumber *>().toStyleValue(propertyValue);
}
- (void)setTextPadding:(MGLStyleValue<NSNumber *> *)textPadding {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textPadding);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textPadding);
self.rawLayer->setTextPadding(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textPadding {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextPadding() ?: self.rawLayer->getDefaultTextPadding();
+ auto propertyValue = self.rawLayer->getTextPadding();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextPadding());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -729,21 +820,27 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)textPitchAlignment {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextPitchAlignment() ?: self.rawLayer->getDefaultTextPitchAlignment();
+ auto propertyValue = self.rawLayer->getTextPitchAlignment();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumStyleValue(self.rawLayer->getDefaultTextPitchAlignment());
+ }
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toEnumStyleValue(propertyValue);
}
- (void)setTextRotation:(MGLStyleValue<NSNumber *> *)textRotation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textRotation);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(textRotation);
self.rawLayer->setTextRotate(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textRotation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextRotate() ?: self.rawLayer->getDefaultTextRotate();
+ auto propertyValue = self.rawLayer->getTextRotate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultTextRotate());
+ }
return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
}
@@ -764,22 +861,28 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)textRotationAlignment {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextRotationAlignment() ?: self.rawLayer->getDefaultTextRotationAlignment();
+ auto propertyValue = self.rawLayer->getTextRotationAlignment();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(self.rawLayer->getDefaultTextRotationAlignment());
+ }
return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextRotationAlignment>().toEnumStyleValue(propertyValue);
}
- (void)setTextTransform:(MGLStyleValue<NSValue *> *)textTransform {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toEnumPropertyValue(textTransform);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenPropertyValue(textTransform);
self.rawLayer->setTextTransform(mbglValue);
}
- (MGLStyleValue<NSValue *> *)textTransform {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextTransform() ?: self.rawLayer->getDefaultTextTransform();
- return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toEnumStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextTransform();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextTransform());
+ }
+ return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toDataDrivenStyleValue(propertyValue);
}
#pragma mark - Accessing the Paint Attributes
@@ -787,84 +890,102 @@ namespace mbgl {
- (void)setIconColor:(MGLStyleValue<MGLColor *> *)iconColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(iconColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconColor);
self.rawLayer->setIconColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)iconColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconColor() ?: self.rawLayer->getDefaultIconColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloBlur:(MGLStyleValue<NSNumber *> *)iconHaloBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconHaloBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloBlur);
self.rawLayer->setIconHaloBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconHaloBlur {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconHaloBlur() ?: self.rawLayer->getDefaultIconHaloBlur();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconHaloBlur();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloBlur());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloColor:(MGLStyleValue<MGLColor *> *)iconHaloColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(iconHaloColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(iconHaloColor);
self.rawLayer->setIconHaloColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)iconHaloColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconHaloColor() ?: self.rawLayer->getDefaultIconHaloColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconHaloColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconHaloWidth:(MGLStyleValue<NSNumber *> *)iconHaloWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconHaloWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconHaloWidth);
self.rawLayer->setIconHaloWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconHaloWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconHaloWidth() ?: self.rawLayer->getDefaultIconHaloWidth();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconHaloWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconHaloWidth());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconOpacity:(MGLStyleValue<NSNumber *> *)iconOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(iconOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(iconOpacity);
self.rawLayer->setIconOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)iconOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconOpacity() ?: self.rawLayer->getDefaultIconOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getIconOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultIconOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setIconTranslation:(MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(iconTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(iconTranslation);
self.rawLayer->setIconTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)iconTranslation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconTranslate() ?: self.rawLayer->getDefaultIconTranslate();
+ auto propertyValue = self.rawLayer->getIconTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultIconTranslate());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -885,7 +1006,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)iconTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getIconTranslateAnchor() ?: self.rawLayer->getDefaultIconTranslateAnchor();
+ auto propertyValue = self.rawLayer->getIconTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultIconTranslateAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLIconTranslationAnchor>().toEnumStyleValue(propertyValue);
}
@@ -899,84 +1023,102 @@ namespace mbgl {
- (void)setTextColor:(MGLStyleValue<MGLColor *> *)textColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(textColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textColor);
self.rawLayer->setTextColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)textColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextColor() ?: self.rawLayer->getDefaultTextColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloBlur:(MGLStyleValue<NSNumber *> *)textHaloBlur {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textHaloBlur);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloBlur);
self.rawLayer->setTextHaloBlur(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textHaloBlur {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextHaloBlur() ?: self.rawLayer->getDefaultTextHaloBlur();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextHaloBlur();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloBlur());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloColor:(MGLStyleValue<MGLColor *> *)textHaloColor {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue(textHaloColor);
+ auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenPropertyValue(textHaloColor);
self.rawLayer->setTextHaloColor(mbglValue);
}
- (MGLStyleValue<MGLColor *> *)textHaloColor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextHaloColor() ?: self.rawLayer->getDefaultTextHaloColor();
- return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextHaloColor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloColor());
+ }
+ return MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextHaloWidth:(MGLStyleValue<NSNumber *> *)textHaloWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textHaloWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textHaloWidth);
self.rawLayer->setTextHaloWidth(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textHaloWidth {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextHaloWidth() ?: self.rawLayer->getDefaultTextHaloWidth();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextHaloWidth();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextHaloWidth());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextOpacity:(MGLStyleValue<NSNumber *> *)textOpacity {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue(textOpacity);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(textOpacity);
self.rawLayer->setTextOpacity(mbglValue);
}
- (MGLStyleValue<NSNumber *> *)textOpacity {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextOpacity() ?: self.rawLayer->getDefaultTextOpacity();
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ auto propertyValue = self.rawLayer->getTextOpacity();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultTextOpacity());
+ }
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setTextTranslation:(MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toPropertyValue(textTranslation);
+ auto mbglValue = MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toInterpolatablePropertyValue(textTranslation);
self.rawLayer->setTextTranslate(mbglValue);
}
- (MGLStyleValue<NSValue *> *)textTranslation {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextTranslate() ?: self.rawLayer->getDefaultTextTranslate();
+ auto propertyValue = self.rawLayer->getTextTranslate();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(self.rawLayer->getDefaultTextTranslate());
+ }
return MGLStyleValueTransformer<std::array<float, 2>, NSValue *>().toStyleValue(propertyValue);
}
@@ -997,7 +1139,10 @@ namespace mbgl {
- (MGLStyleValue<NSValue *> *)textTranslationAnchor {
MGLAssertStyleLayerIsValid();
- auto propertyValue = self.rawLayer->getTextTranslateAnchor() ?: self.rawLayer->getDefaultTextTranslateAnchor();
+ auto propertyValue = self.rawLayer->getTextTranslateAnchor();
+ if (propertyValue.isUndefined()) {
+ return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(self.rawLayer->getDefaultTextTranslateAnchor());
+ }
return MGLStyleValueTransformer<mbgl::style::TranslateAnchorType, NSValue *, mbgl::style::TranslateAnchorType, MGLTextTranslationAnchor>().toEnumStyleValue(propertyValue);
}
diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.h b/platform/darwin/src/MGLTilePyramidOfflineRegion.h
index 4c6237702d..31e5a41920 100644
--- a/platform/darwin/src/MGLTilePyramidOfflineRegion.h
+++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.h
@@ -15,10 +15,10 @@ MGL_EXPORT
/**
URL of the style whose resources are required for offline viewing.
-
+
In addition to the JSON stylesheet, different styles may require different font
glyphs, sprite sheets, and other resources.
-
+
The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s
map ID (`mapbox://styles/{user}/{style}`).
*/
@@ -32,14 +32,14 @@ MGL_EXPORT
/**
The minimum zoom level for which to download tiles and other resources.
-
+
For more information about zoom levels, `-[MGLMapView zoomLevel]`.
*/
@property (nonatomic, readonly) double minimumZoomLevel;
/**
The maximum zoom level for which to download tiles and other resources.
-
+
For more information about zoom levels, `-[MGLMapView zoomLevel]`.
*/
@property (nonatomic, readonly) double maximumZoomLevel;
@@ -49,9 +49,9 @@ MGL_EXPORT
/**
Initializes a newly created offline region with the given style URL, geographic
coordinate bounds, and range of zoom levels.
-
+
This is the designated initializer for `MGLTilePyramidOfflineRegion`.
-
+
@param styleURL URL of the map style for which to download resources. The URL
may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s map
ID (`mapbox://styles/{user}/{style}`). Specify `nil` for the default style.
diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
index f128fbb256..e0d56484bf 100644
--- a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
+++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm
@@ -35,7 +35,7 @@
if (!styleURL) {
styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
}
-
+
if (!styleURL.scheme) {
[NSException raise:@"Invalid style URL" format:
@"%@ does not support setting a relative file URL as the style URL. "
@@ -44,7 +44,7 @@
@"For Mapbox-hosted styles, use the mapbox: scheme.",
NSStringFromClass([self class])];
}
-
+
_styleURL = styleURL;
_bounds = bounds;
_minimumZoomLevel = minimumZoomLevel;
@@ -80,7 +80,7 @@
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(sw, ne);
double minimumZoomLevel = [coder decodeDoubleForKey:@"minimumZoomLevel"];
double maximumZoomLevel = [coder decodeDoubleForKey:@"maximumZoomLevel"];
-
+
return [self initWithStyleURL:styleURL bounds:bounds fromZoomLevel:minimumZoomLevel toZoomLevel:maximumZoomLevel];
}
@@ -106,7 +106,7 @@
if (![other isKindOfClass:[self class]]) {
return NO;
}
-
+
MGLTilePyramidOfflineRegion *otherRegion = other;
return (_minimumZoomLevel == otherRegion->_minimumZoomLevel
&& _maximumZoomLevel == otherRegion->_maximumZoomLevel
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index 99d23f4add..bc29b0f95c 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -16,7 +16,7 @@ typedef NSString *MGLTileSourceOption NS_STRING_ENUM;
/**
An `NSNumber` object containing an unsigned integer that specifies the minimum
zoom level at which to display tiles from the source.
-
+
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMaximumZoomLevel`, if specified. The default value for this
option is 0.
@@ -30,7 +30,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMinimumZoomLevel;
/**
An `NSNumber` object containing an unsigned integer that specifies the maximum
zoom level at which to display tiles from the source.
-
+
The value should be between 0 and 22, inclusive, and less than
`MGLTileSourceOptionMinimumZoomLevel`, if specified. The default value for this
option is 22.
@@ -46,7 +46,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionMaximumZoomLevel;
An HTML string defining the buttons to be displayed in an action sheet when the
source is part of a map view’s style and the map view’s attribution button is
pressed.
-
+
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
@@ -61,7 +61,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLSt
An array of `MGLAttributionInfo` objects defining the buttons to be displayed
in an action sheet when the source is part of a map view’s style and the map
view’s attribution button is pressed.
-
+
By default, no attribution statements are displayed.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
@@ -69,7 +69,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
/**
An HTML string defining the buttons to be displayed in the map view’s
attribution view when the source is part of the map view’s style.
-
+
By default, no attribution statements are displayed. If the
`MGLTileSourceOptionAttributionInfos` option is specified, this option is
ignored.
@@ -84,7 +84,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionHTMLSt
An array of `MGLAttributionInfo` objects defining the buttons to be displayed
in the map view’s attribution view when the source is part of the map view’s
style.
-
+
By default, no attribution statements are displayed.
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
@@ -94,7 +94,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
An `NSNumber` object containing an unsigned integer that specifies the tile
coordinate system for the source’s tile URLs. The integer corresponds to one of
the constants described in `MGLTileCoordinateSystem`.
-
+
The default value for this option is `MGLTileCoordinateSystemXYZ`.
This option corresponds to the `scheme` key in the
@@ -111,16 +111,16 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
/**
The origin is at the top-left (northwest), and `y` values increase
southwards.
-
+
This tile coordinate system is used by Mapbox and OpenStreetMap tile
servers.
*/
MGLTileCoordinateSystemXYZ = 0,
-
+
/**
The origin is at the bottom-left (southwest), and `y` values increase
northwards.
-
+
This tile coordinate system is used by tile servers that conform to the
<a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">Tile Map Service Specification</a>.
*/
@@ -135,7 +135,7 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
A tile source is added to an `MGLStyle` object along with one or more
`MGLRasterStyleLayer` or `MGLVectorStyleLayer` objects. Use a style layer to
control the appearance of content supplied by the tile source.
-
+
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of `MGLRasterSource` and
`MGLVectorSource`.
@@ -150,15 +150,15 @@ MGL_EXPORT
/**
Returns a tile source initialized with an identifier and configuration URL.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
-
+
The URL may be a full HTTP or HTTPS URL or, for tile sets hosted by Mapbox, a
Mapbox URL indicating a map identifier (`mapbox://<mapid>`). The URL should
point to a JSON file that conforms to the
<a href="https://github.com/mapbox/tilejson-spec/">TileJSON specification</a>.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param configurationURL A URL to a TileJSON configuration file describing the
@@ -170,27 +170,27 @@ MGL_EXPORT
/**
Returns a tile source initialized an identifier, tile URL templates, and
options.
-
+
After initializing and configuring the source, add it to a map view’s style
using the `-[MGLStyle addSource:]` method.
-
+
#### Tile URL templates
-
+
Tile URL templates are strings that specify the URLs of the tile images to
load. Each template resembles an absolute URL, but with any number of
placeholder strings that the source evaluates based on the tile it needs to
load. For example:
-
+
<ul>
<li><code>http://www.example.com/tiles/{z}/{x}/{y}.pbf</code> could be
evaluated as <code>http://www.example.com/tiles/14/6/9.pbf</code>.</li>
<li><code>http://www.example.com/tiles/{z}/{x}/{y}{ratio}.png</code> could be
evaluated as <code>http://www.example.com/tiles/14/6/9@2x.png</code>.</li>
</ul>
-
+
Tile sources support the following placeholder strings in tile URL templates,
all of which are optional:
-
+
<table>
<thead>
<tr><th>Placeholder string</th><th>Description</th></tr>
@@ -256,11 +256,11 @@ MGL_EXPORT
</tr>
</tbody>
</table>
-
+
For more information about the `{x}`, `{y}`, and `{z}` placeholder strings,
consult the
<a href="https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames">OpenStreetMap Wiki</a>.
-
+
@param identifier A string that uniquely identifies the source in the style to
which it is added.
@param tileURLTemplates An array of tile URL template strings. Only the first
@@ -288,7 +288,7 @@ MGL_EXPORT
/**
An array of `MGLAttributionInfo` objects that define the attribution
statements to be displayed when the map is shown to the user.
-
+
By default, this array is empty. If the source is initialized with a
configuration URL, this array is also empty until the configuration JSON file
is loaded.
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index 1aef81d53c..aa2a299a46 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -53,11 +53,11 @@ const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem = @"MGLTileSou
mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) {
mbgl::Tileset tileSet;
-
+
for (NSString *tileURLTemplate in tileURLTemplates) {
tileSet.tiles.push_back(tileURLTemplate.UTF8String);
}
-
+
// set the minimum / maximum zoom range to the values specified by this class if they
// were set. otherwise, use the core objects default values
if (NSNumber *minimumZoomLevel = options[MGLTileSourceOptionMinimumZoomLevel]) {
@@ -78,7 +78,7 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionMinimumZoomLevel must be less than MGLTileSourceOptionMaximumZoomLevel."];
}
-
+
if (NSString *attribution = options[MGLTileSourceOptionAttributionHTMLString]) {
if (![attribution isKindOfClass:[NSString class]]) {
[NSException raise:NSInvalidArgumentException
@@ -86,13 +86,13 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
}
tileSet.attribution = attribution.UTF8String;
}
-
+
if (NSArray *attributionInfos = options[MGLTileSourceOptionAttributionInfos]) {
if (![attributionInfos isKindOfClass:[NSArray class]]) {
[NSException raise:NSInvalidArgumentException
format:@"MGLTileSourceOptionAttributionInfos must be set to a string."];
}
-
+
NSAttributedString *attributedString = [MGLAttributionInfo attributedStringForAttributionInfos:attributionInfos];
#if TARGET_OS_IPHONE
static NSString * const NSExcludedElementsDocumentAttribute = @"ExcludedElements";
@@ -107,7 +107,7 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
tileSet.attribution = html.UTF8String;
}
-
+
if (NSNumber *tileCoordinateSystemNumber = options[MGLTileSourceOptionTileCoordinateSystem]) {
if (![tileCoordinateSystemNumber isKindOfClass:[NSValue class]]) {
[NSException raise:NSInvalidArgumentException
@@ -124,6 +124,6 @@ mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTem
break;
}
}
-
+
return tileSet;
}
diff --git a/platform/darwin/src/MGLTileSource_Private.h b/platform/darwin/src/MGLTileSource_Private.h
index 8da69274f2..0d9876d412 100644
--- a/platform/darwin/src/MGLTileSource_Private.h
+++ b/platform/darwin/src/MGLTileSource_Private.h
@@ -15,7 +15,7 @@ namespace mbgl {
/**
An HTML string to be displayed as attribution when the map is shown to a user.
-
+
The default value is `nil`. If the source is initialized with a configuration
URL, this property is also `nil` until the configuration JSON file is loaded.
*/
@@ -24,7 +24,7 @@ namespace mbgl {
/**
A structured representation of the `attribution` property. The default value is
`nil`.
-
+
@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.
*/
diff --git a/platform/darwin/src/MGLValueEvaluator.h b/platform/darwin/src/MGLValueEvaluator.h
index b53cdaa8d2..2779deba90 100644
--- a/platform/darwin/src/MGLValueEvaluator.h
+++ b/platform/darwin/src/MGLValueEvaluator.h
@@ -10,27 +10,27 @@ public:
id operator()(const mbgl::NullValue &) const {
return [NSNull null];
}
-
+
id operator()(const bool &value) const {
return value ? @YES : @NO;
}
-
+
id operator()(const uint64_t &value) const {
return @(value);
}
-
+
id operator()(const int64_t &value) const {
return @(value);
}
-
+
id operator()(const double &value) const {
return @(value);
}
-
+
id operator()(const std::string &value) const {
return @(value.c_str());
}
-
+
id operator()(const std::vector<mbgl::Value> &values) const {
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:values.size()];
for (const auto &v : values) {
@@ -38,7 +38,7 @@ public:
}
return objects;
}
-
+
id operator()(const std::unordered_map<std::string, mbgl::Value> &items) const {
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:items.size()];
for (auto &item : items) {
diff --git a/platform/darwin/src/MGLVectorSource.h b/platform/darwin/src/MGLVectorSource.h
index bfa52f5b49..2322c62f29 100644
--- a/platform/darwin/src/MGLVectorSource.h
+++ b/platform/darwin/src/MGLVectorSource.h
@@ -12,22 +12,22 @@ NS_ASSUME_NONNULL_BEGIN
A vector source is added to an `MGLStyle` object along with one or more
`MGLVectorStyleLayer` objects. A vector style layer defines the appearance of
any content supplied by the vector source.
-
+
Each
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-vector"><code>vector</code></a>
source defined by the style JSON file is represented at runtime by an
`MGLVectorSource` object that you can use to initialize new style layers. You
can also add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
-
+
Within each vector tile, each geometric coordinate must lie between
−1&nbsp;×&nbsp;<var>extent</var> and
(<var>extent</var>&nbsp;×&nbsp;2)&nbsp;−&nbsp;1, inclusive. Any vector style
layer initialized with a vector source must have a non-`nil` value in its
`sourceLayerIdentifier` property.
-
+
### Example
-
+
```swift
let source = MGLVectorSource(identifier: "pois", tileURLTemplates: ["https://example.com/vector-tiles/{z}/{x}/{y}.mvt"], options: [
.minimumZoomLevel: 9,
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index 8fda528546..94511900c1 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -33,7 +33,7 @@
- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
if (self = [super initWithIdentifier:identifier tileURLTemplates:tileURLTemplates options:options]) {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
-
+
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
_pendingSource = std::move(source);
self.rawSource = _pendingSource.get();
@@ -56,9 +56,20 @@
}
- (void)removeFromMapView:(MGLMapView *)mapView {
+ if (self.rawSource != mapView.mbglMap->getSource(self.identifier.UTF8String)) {
+ return;
+ }
+
auto removedSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
- _pendingSource = std::move(reinterpret_cast<std::unique_ptr<mbgl::style::VectorSource> &>(removedSource));
+ mbgl::style::VectorSource *source = dynamic_cast<mbgl::style::VectorSource *>(removedSource.get());
+ if (!source) {
+ return;
+ }
+
+ removedSource.release();
+
+ _pendingSource = std::unique_ptr<mbgl::style::VectorSource>(source);
self.rawSource = _pendingSource.get();
}
diff --git a/platform/darwin/src/MGLVectorStyleLayer.h b/platform/darwin/src/MGLVectorStyleLayer.h
index ca09c11716..c6193e6046 100644
--- a/platform/darwin/src/MGLVectorStyleLayer.h
+++ b/platform/darwin/src/MGLVectorStyleLayer.h
@@ -8,7 +8,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
`MGLVectorStyleLayer` is an abstract superclass for style layers whose content
is defined by an `MGLShapeSource` or `MGLVectorSource` object.
-
+
Do not create instances of this class directly, and do not create your own
subclasses of this class. Instead, create instances of the following concrete
subclasses: `MGLCircleStyleLayer`, `MGLFillStyleLayer`, `MGLLineStyleLayer`,
@@ -27,15 +27,15 @@ MGL_EXPORT
/**
The style layer’s predicate.
-
+
Use the style layer’s predicate to include only the features in the source
layer that satisfy a condition that you define. If the style layer initially
comes from the style, its predicate corresponds to the
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#layer-filter">`filter`</a>
property in the style JSON.
-
+
The following comparison operators are supported.
-
+
<ul>
<li><code>NSEqualToPredicateOperatorType</code> (<code>=</code>, <code>==</code>)</li>
<li><code>NSGreaterThanOrEqualToPredicateOperatorType</code> (<code>>=</code>, <code>=></code>)</li>
@@ -45,35 +45,35 @@ MGL_EXPORT
<li><code>NSNotEqualToPredicateOperatorType</code> (<code>!=</code>, <code><></code>)</li>
<li><code>NSBetweenPredicateOperatorType</code> (<code>BETWEEN</code>)</li>
</ul>
-
+
The following compound operators are supported:
-
+
<ul>
<li><code>NSAndPredicateType</code> (<code>AND</code>, <code>&&</code>)</li>
<li><code>NSOrPredicateType</code> (<code>OR</code>, <code>||</code>)</li>
<li><code>NSNotPredicateType</code> (<code>NOT</code>, <code>!</code>)</li>
</ul>
-
+
The following aggregate operators are supported:
-
+
<ul>
<li><code>NSInPredicateOperatorType</code> (<code>IN</code>)</li>
<li><code>NSContainsPredicateOperatorType</code> (<code>CONTAINS</code>)</li>
</ul>
-
+
To test whether a feature has or lacks a specific attribute, compare the
attribute to `NULL` or `NIL`. Predicates created using the
`+[NSPredicate predicateWithValue:]` method are also supported. String
operators and custom operators are not supported.
-
+
For details about the predicate format string syntax, consult the “Predicate
Format String Syntax” chapter of the
“<a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Predicates/">Predicate Programming Guide</a>”
in Apple developer documentation.
-
+
The predicate's left-hand expression must be a string that identifies a feature
attribute or, alternatively, one of the following special attributes:
-
+
<table>
<thead>
<tr><th>Attribute</th><th>Meaning</th></tr>
@@ -115,33 +115,33 @@ MGL_EXPORT
</tr>
</tbody>
</table>
-
+
The predicate’s right-hand expression must be an `NSString` (to match strings)
or `NSNumber` (to match numbers, including Boolean values) or an array of
`NSString`s or `NSNumber`s, depending on the operator and the type of values
expected for the attribute being tested. For floating-point values, use
`-[NSNumber numberWithDouble:]` instead of `-[NSNumber numberWithFloat:]`
to avoid precision issues.
-
+
Automatic type casting is not performed. Therefore, a feature only matches this
predicate if its value for the attribute in question is of the same type as the
value specified in the predicate. Also, operator modifiers such as `c` (for
case insensitivity), `d` (for diacritic insensitivity), and `l` (for locale
sensitivity) are unsupported for comparison and aggregate operators that are
used in the predicate.
-
- It is possible to create expressions that contain special characters in the
- predicate format syntax. This includes the `$` in the `$id` and `$type` special
+
+ It is possible to create expressions that contain special characters in the
+ predicate format syntax. This includes the `$` in the `$id` and `$type` special
style attributes and also `hyphen-minus` and `tag:subtag`. However, you must use
`%K` in the format string to represent these variables:
`@"%K == 'LineString'", @"$type"`.
-
+
### Example
-
+
To filter the layer to include only the features whose `index` attribute is 5
or 10 and whose `ele` attribute is at least 1,500, you could create an
`NSCompoundPredicate` along these lines:
-
+
```swift
let layer = MGLLineStyleLayer(identifier: "contour", source: terrain)
layer.sourceLayerIdentifier = "contours"
diff --git a/platform/darwin/src/NSArray+MGLAdditions.mm b/platform/darwin/src/NSArray+MGLAdditions.mm
index 8ec344f580..3cab7ff427 100644
--- a/platform/darwin/src/NSArray+MGLAdditions.mm
+++ b/platform/darwin/src/NSArray+MGLAdditions.mm
@@ -50,15 +50,15 @@
- (std::vector<CLLocationCoordinate2D>)mgl_coordinates {
NSUInteger numberOfCoordinates = [self count];
CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(numberOfCoordinates * sizeof(CLLocationCoordinate2D));
-
+
for (NSUInteger i = 0; i < numberOfCoordinates; i++) {
coords[i] = CLLocationCoordinate2DMake([self[i][@"latitude"] doubleValue],
[self[i][@"longitude"] doubleValue]);
}
-
+
std::vector<CLLocationCoordinate2D> coordinates = { coords, coords + numberOfCoordinates };
free(coords);
-
+
return coordinates;
}
diff --git a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
index 58b37fae0e..ac2d598d05 100644
--- a/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm
@@ -5,8 +5,7 @@
@implementation NSComparisonPredicate (MGLAdditions)
-- (mbgl::style::Filter)mgl_filter
-{
+- (mbgl::style::Filter)mgl_filter {
NSExpression *leftExpression = self.leftExpression;
NSExpression *rightExpression = self.rightExpression;
NSExpressionType leftType = leftExpression.expressionType;
@@ -19,13 +18,32 @@
eqFilter.key = self.mgl_keyPath.UTF8String;
eqFilter.value = self.mgl_constantValue;
+ // Convert $type == to TypeEqualsFilter.
+ if (eqFilter.key == "$type") {
+ mbgl::style::TypeEqualsFilter typeEqFilter;
+ typeEqFilter.value = self.mgl_featureType;
+ return typeEqFilter;
+ }
+
+ // Convert $id == to IdentifierEqualsFilter.
+ if (eqFilter.key == "$id") {
+ // Convert $id == nil to NotHasIdentifierFilter.
+ if (eqFilter.value.is<mbgl::NullValue>()) {
+ return mbgl::style::NotHasIdentifierFilter();
+ }
+
+ mbgl::style::IdentifierEqualsFilter idEqFilter;
+ idEqFilter.value = self.mgl_featureIdentifier;
+ return idEqFilter;
+ }
+
// Convert == nil to NotHasFilter.
if (eqFilter.value.is<mbgl::NullValue>()) {
mbgl::style::NotHasFilter notHasFilter;
notHasFilter.key = eqFilter.key;
return notHasFilter;
}
-
+
return eqFilter;
}
case NSNotEqualToPredicateOperatorType: {
@@ -33,13 +51,32 @@
neFilter.key = self.mgl_keyPath.UTF8String;
neFilter.value = self.mgl_constantValue;
+ // Convert $type != to TypeNotEqualsFilter.
+ if (neFilter.key == "$type") {
+ mbgl::style::TypeNotEqualsFilter typeNeFilter;
+ typeNeFilter.value = self.mgl_featureType;
+ return typeNeFilter;
+ }
+
+ // Convert $id != to IdentifierNotEqualsFilter.
+ if (neFilter.key == "$id") {
+ // Convert $id != nil to HasIdentifierFilter.
+ if (neFilter.value.is<mbgl::NullValue>()) {
+ return mbgl::style::HasIdentifierFilter();
+ }
+
+ mbgl::style::IdentifierNotEqualsFilter idNeFilter;
+ idNeFilter.value = self.mgl_featureIdentifier;
+ return idNeFilter;
+ }
+
// Convert != nil to HasFilter.
if (neFilter.value.is<mbgl::NullValue>()) {
mbgl::style::HasFilter hasFilter;
hasFilter.key = neFilter.key;
return hasFilter;
}
-
+
return neFilter;
}
case NSGreaterThanPredicateOperatorType: {
@@ -103,6 +140,21 @@
[NSException raise:NSInvalidArgumentException
format:@"Predicate cannot compare values IN attribute."];
}
+
+ // Convert $type IN to TypeInFilter.
+ if ([leftExpression.keyPath isEqualToString:@"$type"]) {
+ mbgl::style::TypeInFilter typeInFilter;
+ typeInFilter.values = rightExpression.mgl_aggregateFeatureType;
+ return typeInFilter;
+ }
+
+ // Convert $id IN to IdentifierInFilter.
+ if ([leftExpression.keyPath isEqualToString:@"$id"]) {
+ mbgl::style::IdentifierInFilter idInFilter;
+ idInFilter.values = rightExpression.mgl_aggregateFeatureIdentifier;
+ return idInFilter;
+ }
+
mbgl::style::InFilter inFilter;
inFilter.key = leftExpression.keyPath.UTF8String;
inFilter.values = rightExpression.mgl_aggregateMBGLValue;
@@ -117,6 +169,21 @@
[NSException raise:NSInvalidArgumentException
format:@"Predicate cannot compare attribute CONTAINS values."];
}
+
+ // Convert CONTAINS $type to TypeInFilter.
+ if ([rightExpression.keyPath isEqualToString:@"$type"]) {
+ mbgl::style::TypeInFilter typeInFilter;
+ typeInFilter.values = leftExpression.mgl_aggregateFeatureType;
+ return typeInFilter;
+ }
+
+ // Convert CONTAINS $id to IdentifierInFilter.
+ if ([rightExpression.keyPath isEqualToString:@"$id"]) {
+ mbgl::style::IdentifierInFilter idInFilter;
+ idInFilter.values = leftExpression.mgl_aggregateFeatureIdentifier;
+ return idInFilter;
+ }
+
mbgl::style::InFilter inFilter;
inFilter.key = rightExpression.keyPath.UTF8String;
inFilter.values = leftExpression.mgl_aggregateMBGLValue;
@@ -155,7 +222,7 @@
[NSException raise:NSInvalidArgumentException
format:@"NSPredicateOperatorType:%lu is not supported.", (unsigned long)self.predicateOperatorType];
}
-
+
return {};
}
@@ -169,7 +236,7 @@
} else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
return rightExpression.keyPath;
}
-
+
[NSException raise:NSInvalidArgumentException
format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
return nil;
@@ -192,4 +259,38 @@
return value;
}
+- (mbgl::FeatureType)mgl_featureType {
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ mbgl::FeatureType type;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ type = rightExpression.mgl_featureType;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ type = leftExpression.mgl_featureType;
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ }
+ return type;
+}
+
+- (mbgl::FeatureIdentifier)mgl_featureIdentifier {
+ NSExpression *leftExpression = self.leftExpression;
+ NSExpression *rightExpression = self.rightExpression;
+ NSExpressionType leftType = leftExpression.expressionType;
+ NSExpressionType rightType = rightExpression.expressionType;
+ mbgl::FeatureIdentifier identifier;
+ if (leftType == NSKeyPathExpressionType && rightType == NSConstantValueExpressionType) {
+ identifier = rightExpression.mgl_featureIdentifier;
+ } else if (leftType == NSConstantValueExpressionType && rightType == NSKeyPathExpressionType) {
+ identifier = leftExpression.mgl_featureIdentifier;
+ } else {
+ [NSException raise:NSInvalidArgumentException
+ format:@"Comparison predicate must compare an attribute (as a key path) to a constant or vice versa."];
+ }
+ return identifier;
+}
+
@end
diff --git a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
index 2697467198..0039b5af82 100644
--- a/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSCompoundPredicate+MGLAdditions.mm
@@ -21,19 +21,19 @@
NSAssert(self.subpredicates.count <= 1, @"NOT predicate cannot have multiple subpredicates.");
NSPredicate *subpredicate = self.subpredicates.firstObject;
mbgl::style::Filter subfilter = subpredicate.mgl_filter;
-
+
// Convert NOT(!= nil) to NotHasFilter.
if (subfilter.is<mbgl::style::HasFilter>()) {
auto hasFilter = subfilter.get<mbgl::style::HasFilter>();
return mbgl::style::NotHasFilter { .key = hasFilter.key };
}
-
+
// Convert NOT(== nil) to HasFilter.
if (subfilter.is<mbgl::style::NotHasFilter>()) {
auto hasFilter = subfilter.get<mbgl::style::NotHasFilter>();
return mbgl::style::HasFilter { .key = hasFilter.key };
}
-
+
// Convert NOT(IN) or NOT(CONTAINS) to NotInFilter.
if (subfilter.is<mbgl::style::InFilter>()) {
auto inFilter = subfilter.get<mbgl::style::InFilter>();
@@ -42,7 +42,7 @@
notInFilter.values = inFilter.values;
return notInFilter;
}
-
+
// Convert NOT(), NOT(AND), NOT(NOT), NOT(==), etc. into NoneFilter.
mbgl::style::NoneFilter noneFilter;
if (subfilter.is<mbgl::style::AnyFilter>()) {
@@ -64,7 +64,7 @@
return filter;
}
}
-
+
[NSException raise:@"Compound predicate type not handled"
format:@""];
return {};
diff --git a/platform/darwin/src/NSData+MGLAdditions.mm b/platform/darwin/src/NSData+MGLAdditions.mm
index ef171c5e1e..97c3bb4a26 100644
--- a/platform/darwin/src/NSData+MGLAdditions.mm
+++ b/platform/darwin/src/NSData+MGLAdditions.mm
@@ -8,7 +8,7 @@
{
std::string string(static_cast<const char*>(self.bytes), self.length);
std::string compressed_string = mbgl::util::compress(string);
-
+
return [NSData dataWithBytes:&compressed_string[0] length:compressed_string.length()];
}
@@ -16,7 +16,7 @@
{
std::string string(static_cast<const char*>(self.bytes), self.length);
std::string decompressed_string = mbgl::util::decompress(string);
-
+
return [NSData dataWithBytes:&decompressed_string[0] length:decompressed_string.length()];
}
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h
index c60d6d78ba..491ed5a536 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.h
+++ b/platform/darwin/src/NSExpression+MGLAdditions.h
@@ -8,7 +8,10 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) mbgl::Value mgl_constantMBGLValue;
@property (nonatomic, readonly) std::vector<mbgl::Value> mgl_aggregateMBGLValue;
+@property (nonatomic, readonly) mbgl::FeatureType mgl_featureType;
+@property (nonatomic, readonly) std::vector<mbgl::FeatureType> mgl_aggregateFeatureType;
@property (nonatomic, readonly) mbgl::FeatureIdentifier mgl_featureIdentifier;
+@property (nonatomic, readonly) std::vector<mbgl::FeatureIdentifier> mgl_aggregateFeatureIdentifier;
@end
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index b095091b17..a7759cda9d 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -1,5 +1,12 @@
#import "NSExpression+MGLAdditions.h"
+#import "MGLTypes.h"
+#if TARGET_OS_IPHONE
+ #import "UIColor+MGLAdditions.h"
+#else
+ #import "NSColor+MGLAdditions.h"
+#endif
+
@implementation NSExpression (MGLAdditions)
- (std::vector<mbgl::Value>)mgl_aggregateMBGLValue {
@@ -56,6 +63,9 @@
// We use long long here to avoid any truncation.
return { (int64_t)number.longLongValue };
}
+ } else if ([value isKindOfClass:[MGLColor class]]) {
+ auto hexString = [(MGLColor *)value mgl_color].stringify();
+ return { hexString };
} else if (value && value != [NSNull null]) {
[NSException raise:NSInvalidArgumentException
format:@"Can’t convert %s:%@ to mbgl::Value", [value objCType], value];
@@ -63,9 +73,70 @@
return {};
}
+- (std::vector<mbgl::FeatureType>)mgl_aggregateFeatureType {
+ if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
+ std::vector<mbgl::FeatureType> convertedValues;
+ for (id value in self.constantValue) {
+ NSExpression *expression = value;
+ if (![expression isKindOfClass:[NSExpression class]]) {
+ expression = [NSExpression expressionForConstantValue:expression];
+ }
+ convertedValues.push_back(expression.mgl_featureType);
+ }
+ return convertedValues;
+ }
+ [NSException raise:NSInvalidArgumentException
+ format:@"Constant value expression must contain an array or set."];
+ return {};
+}
+
+- (mbgl::FeatureType)mgl_featureType {
+ id value = self.constantValue;
+ if ([value isKindOfClass:NSString.class]) {
+ if ([value isEqualToString:@"Point"]) {
+ return mbgl::FeatureType::Point;
+ }
+ if ([value isEqualToString:@"LineString"]) {
+ return mbgl::FeatureType::LineString;
+ }
+ if ([value isEqualToString:@"Polygon"]) {
+ return mbgl::FeatureType::Polygon;
+ }
+ } else if ([value isKindOfClass:NSNumber.class]) {
+ switch ([value integerValue]) {
+ case 1:
+ return mbgl::FeatureType::Point;
+ case 2:
+ return mbgl::FeatureType::LineString;
+ case 3:
+ return mbgl::FeatureType::Polygon;
+ default:
+ break;
+ }
+ }
+ return mbgl::FeatureType::Unknown;
+}
+
+- (std::vector<mbgl::FeatureIdentifier>)mgl_aggregateFeatureIdentifier {
+ if ([self.constantValue isKindOfClass:[NSArray class]] || [self.constantValue isKindOfClass:[NSSet class]]) {
+ std::vector<mbgl::FeatureIdentifier> convertedValues;
+ for (id value in self.constantValue) {
+ NSExpression *expression = value;
+ if (![expression isKindOfClass:[NSExpression class]]) {
+ expression = [NSExpression expressionForConstantValue:expression];
+ }
+ convertedValues.push_back(expression.mgl_featureIdentifier);
+ }
+ return convertedValues;
+ }
+ [NSException raise:NSInvalidArgumentException
+ format:@"Constant value expression must contain an array or set."];
+ return {};
+}
+
- (mbgl::FeatureIdentifier)mgl_featureIdentifier {
mbgl::Value mbglValue = self.mgl_constantMBGLValue;
-
+
if (mbglValue.is<std::string>()) {
return mbglValue.get<std::string>();
}
@@ -78,7 +149,7 @@
if (mbglValue.is<int64_t>()) {
return mbglValue.get<int64_t>();
}
-
+
return {};
}
diff --git a/platform/darwin/src/NSPredicate+MGLAdditions.mm b/platform/darwin/src/NSPredicate+MGLAdditions.mm
index 0ac68095f9..e0511d8740 100644
--- a/platform/darwin/src/NSPredicate+MGLAdditions.mm
+++ b/platform/darwin/src/NSPredicate+MGLAdditions.mm
@@ -4,7 +4,7 @@
class FilterEvaluator {
public:
-
+
NSArray *getPredicates(std::vector<mbgl::style::Filter> filters) {
NSMutableArray *predicates = [NSMutableArray arrayWithCapacity:filters.size()];
for (auto filter : filters) {
@@ -12,52 +12,111 @@ public:
}
return predicates;
}
-
- NSExpression *getValues(std::vector<mbgl::Value> values) {
+
+ template <typename MBGLType>
+ NSExpression *getValues(std::vector<MBGLType> values) {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()];
for (auto value : values) {
- id constantValue = mbgl::Value::visit(value, ValueEvaluator());
+ id constantValue = MBGLType::visit(value, ValueEvaluator());
[array addObject:[NSExpression expressionForConstantValue:constantValue]];
}
return [NSExpression expressionForAggregate:array];
}
+ NSString *getFeatureTypeString(mbgl::FeatureType type) {
+ switch (type) {
+ case mbgl::FeatureType::Point:
+ return @"Point";
+
+ case mbgl::FeatureType::LineString:
+ return @"LineString";
+
+ case mbgl::FeatureType::Polygon:
+ return @"Polygon";
+
+ default:
+ NSCAssert(NO, @"Unrecognized feature type %hhu", type);
+ return nil;
+ }
+ }
+
+ NSExpression *getFeatureTypeStrings(std::vector<mbgl::FeatureType> values) {
+ NSMutableArray *array = [NSMutableArray arrayWithCapacity:values.size()];
+ for (auto value : values) {
+ id typeString = getFeatureTypeString(value);
+ [array addObject:[NSExpression expressionForConstantValue:typeString]];
+ }
+ return [NSExpression expressionForAggregate:array];
+ }
+
NSPredicate *operator()(mbgl::style::NullFilter filter) {
return nil;
}
-
+
NSPredicate *operator()(mbgl::style::EqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::NotEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K != %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::GreaterThanFilter filter) {
return [NSPredicate predicateWithFormat:@"%K > %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::GreaterThanEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K >= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::LessThanFilter filter) {
return [NSPredicate predicateWithFormat:@"%K < %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::LessThanEqualsFilter filter) {
return [NSPredicate predicateWithFormat:@"%K <= %@", @(filter.key.c_str()), mbgl::Value::visit(filter.value, ValueEvaluator())];
}
-
+
NSPredicate *operator()(mbgl::style::InFilter filter) {
return [NSPredicate predicateWithFormat:@"%K IN %@", @(filter.key.c_str()), getValues(filter.values)];
}
-
+
NSPredicate *operator()(mbgl::style::NotInFilter filter) {
return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @(filter.key.c_str()), getValues(filter.values)];
}
+ NSPredicate *operator()(mbgl::style::TypeEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K == %@", @"$type", getFeatureTypeString(filter.value)];
+ }
+
+ NSPredicate *operator()(mbgl::style::TypeNotEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K != %@", @"$type", getFeatureTypeString(filter.value)];
+ }
+
+ NSPredicate *operator()(mbgl::style::TypeInFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K IN %@", @"$type", getFeatureTypeStrings(filter.values)];
+ }
+
+ NSPredicate *operator()(mbgl::style::TypeNotInFilter filter) {
+ return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @"$type", getFeatureTypeStrings(filter.values)];
+ }
+
+ NSPredicate *operator()(mbgl::style::IdentifierEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K == %@", @"$id", mbgl::FeatureIdentifier::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate *operator()(mbgl::style::IdentifierNotEqualsFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K != %@", @"$id", mbgl::FeatureIdentifier::visit(filter.value, ValueEvaluator())];
+ }
+
+ NSPredicate *operator()(mbgl::style::IdentifierInFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K IN %@", @"$id", getValues(filter.values)];
+ }
+
+ NSPredicate *operator()(mbgl::style::IdentifierNotInFilter filter) {
+ return [NSPredicate predicateWithFormat:@"NOT %K IN %@", @"$id", getValues(filter.values)];
+ }
+
NSPredicate *operator()(mbgl::style::AnyFilter filter) {
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count) {
@@ -65,13 +124,13 @@ public:
}
return [NSPredicate predicateWithValue:NO];
}
-
+
NSPredicate *operator()(mbgl::style::AllFilter filter) {
// Convert [all, [>=, key, lower], [<=, key, upper]] to key BETWEEN {lower, upper}
if (filter.filters.size() == 2) {
auto leftFilter = filter.filters[0];
auto rightFilter = filter.filters[1];
-
+
std::string lowerKey;
std::string upperKey;
mbgl::Value lowerBound;
@@ -83,7 +142,7 @@ public:
lowerKey = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().key;
lowerBound = rightFilter.get<mbgl::style::GreaterThanEqualsFilter>().value;
}
-
+
if (leftFilter.is<mbgl::style::LessThanEqualsFilter>()) {
upperKey = leftFilter.get<mbgl::style::LessThanEqualsFilter>().key;
upperBound = leftFilter.get<mbgl::style::LessThanEqualsFilter>().value;
@@ -91,7 +150,7 @@ public:
upperKey = rightFilter.get<mbgl::style::LessThanEqualsFilter>().key;
upperBound = rightFilter.get<mbgl::style::LessThanEqualsFilter>().value;
}
-
+
if (!lowerBound.is<mbgl::NullValue>() && !upperBound.is<mbgl::NullValue>()
&& lowerKey == upperKey) {
return [NSPredicate predicateWithFormat:@"%K BETWEEN {%@, %@}",
@@ -100,14 +159,14 @@ public:
mbgl::Value::visit(upperBound, ValueEvaluator())];
}
}
-
+
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count) {
return [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}
return [NSPredicate predicateWithValue:YES];
}
-
+
NSPredicate *operator()(mbgl::style::NoneFilter filter) {
NSArray *subpredicates = getPredicates(filter.filters);
if (subpredicates.count > 1) {
@@ -119,15 +178,22 @@ public:
return [NSPredicate predicateWithValue:YES];
}
}
-
+
NSPredicate *operator()(mbgl::style::HasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K != nil", @(filter.key.c_str())];
}
-
+
NSPredicate *operator()(mbgl::style::NotHasFilter filter) {
return [NSPredicate predicateWithFormat:@"%K == nil", @(filter.key.c_str())];
}
+ NSPredicate *operator()(mbgl::style::HasIdentifierFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K != nil", @"$id"];
+ }
+
+ NSPredicate *operator()(mbgl::style::NotHasIdentifierFilter filter) {
+ return [NSPredicate predicateWithFormat:@"%K == nil", @"$id"];
+ }
};
@implementation NSPredicate (MGLAdditions)
@@ -138,18 +204,18 @@ public:
{
return mbgl::style::AllFilter();
}
-
+
if ([self isEqual:[NSPredicate predicateWithValue:NO]])
{
return mbgl::style::AnyFilter();
}
-
+
if ([self.predicateFormat hasPrefix:@"BLOCKPREDICATE("])
{
[NSException raise:NSInvalidArgumentException
format:@"Block-based predicates are not supported."];
}
-
+
[NSException raise:NSInvalidArgumentException
format:@"Unrecognized predicate type."];
return {};
diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 246dc084f4..ff72e9d3af 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a title-cased representation of the receiver using the specified
locale.
-
+
@param The locale. For strings presented to users, pass in the current locale
(`+[NSLocale currentLocale]`). To use the system locale, pass in `nil`.
*/
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index 5c32f4b789..371ef4023e 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -45,7 +45,7 @@
scanner.charactersToBeSkipped = nil;
NSString *prefix;
[scanner scanCharactersFromSet:set intoString:&prefix];
-
+
NSString *trimmedString = [self.string stringByTrimmingCharactersInSet:set];
return [self attributedSubstringFromRange:NSMakeRange(prefix.length, trimmedString.length)];
}
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index 4a97c8e115..76388cf2bb 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Creates a new value object containing the specified Core Location geographic
coordinate structure.
-
+
@param coordinate The value for the new object.
@return A new value object that contains the geographic coordinate information.
*/
@@ -29,7 +29,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Creates a new value object containing the specified Mapbox coordinate span
structure.
-
+
@param span The value for the new object.
@return A new value object that contains the coordinate span information.
*/
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Creates a new value object containing the specified Mapbox coordinate bounds
structure.
-
+
@param bounds The value for the new object.
@return A new value object that contains the coordinate bounds information.
*/
@@ -59,7 +59,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Creates a new value object containing the given `MGLOfflinePackProgress`
structure.
-
+
@param progress The value for the new object.
@return A new value object that contains the offline pack progress information.
*/
diff --git a/platform/darwin/src/headless_display_cgl.cpp b/platform/darwin/src/headless_display_cgl.cpp
index 90d187d3db..5b7a1f2bac 100644
--- a/platform/darwin/src/headless_display_cgl.cpp
+++ b/platform/darwin/src/headless_display_cgl.cpp
@@ -18,8 +18,16 @@ HeadlessDisplay::Impl::Impl() {
// TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported
// If it is, use kCGLOGLPVersion_3_2_Core and enable that extension.
CGLPixelFormatAttribute attributes[] = {
- kCGLPFAOpenGLProfile,
- static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy),
+ kCGLPFAOpenGLProfile, static_cast<CGLPixelFormatAttribute>(kCGLOGLPVersion_Legacy),
+ // Not adding kCGLPFAAccelerated, as this will make headless rendering impossible when running in VMs.
+ kCGLPFAClosestPolicy,
+ kCGLPFAAccumSize, static_cast<CGLPixelFormatAttribute>(32),
+ kCGLPFAColorSize, static_cast<CGLPixelFormatAttribute>(24),
+ kCGLPFAAlphaSize, static_cast<CGLPixelFormatAttribute>(8),
+ kCGLPFADepthSize, static_cast<CGLPixelFormatAttribute>(16),
+ kCGLPFAStencilSize, static_cast<CGLPixelFormatAttribute>(8),
+ kCGLPFASupportsAutomaticGraphicsSwitching,
+ kCGLPFAAllowOfflineRenderers, // Allows using the integrated GPU
static_cast<CGLPixelFormatAttribute>(0)
};
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm
index caac2123d8..649cebb47f 100644
--- a/platform/darwin/src/http_file_source.mm
+++ b/platform/darwin/src/http_file_source.mm
@@ -4,7 +4,6 @@
#include <mbgl/util/http_header.hpp>
#include <mbgl/util/async_task.hpp>
-
#include <mbgl/util/version.hpp>
#import <Foundation/Foundation.h>
@@ -100,7 +99,7 @@ public:
NSURLSession* session = nil;
NSString* userAgent = nil;
NSInteger accountType = 0;
-
+
private:
NSString* getUserAgent() const;
NSBundle* getSDKBundle() const;
@@ -108,7 +107,7 @@ private:
NSString *HTTPFileSource::Impl::getUserAgent() const {
NSMutableArray *userAgentComponents = [NSMutableArray array];
-
+
NSBundle *appBundle = [NSBundle mainBundle];
if (appBundle) {
NSString *appName = appBundle.infoDictionary[@"CFBundleName"];
@@ -118,7 +117,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const {
} else {
[userAgentComponents addObject:[NSProcessInfo processInfo].processName];
}
-
+
NSBundle *sdkBundle = HTTPFileSource::Impl::getSDKBundle();
if (sdkBundle) {
NSString *versionString = sdkBundle.infoDictionary[@"MGLSemanticVersionString"];
@@ -130,12 +129,12 @@ NSString *HTTPFileSource::Impl::getUserAgent() const {
sdkBundle.infoDictionary[@"CFBundleName"], versionString]];
}
}
-
+
// Avoid %s here because it inserts hidden bidirectional markers on macOS when the system
// language is set to a right-to-left language.
- [userAgentComponents addObject:[NSString stringWithFormat:@"MapboxGL/%@ (%@)",
- CFSTR(MBGL_VERSION_STRING), CFSTR(MBGL_VERSION_REV)]];
-
+ [userAgentComponents addObject:[NSString stringWithFormat:@"MapboxGL/0.0.0 (%@)",
+ @(mbgl::version::revision)]];
+
NSString *systemName = @"Darwin";
#if TARGET_OS_IPHONE
systemName = @"iOS";
@@ -158,7 +157,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const {
if (systemVersion) {
[userAgentComponents addObject:[NSString stringWithFormat:@"%@/%@", systemName, systemVersion]];
}
-
+
NSString *cpu = nil;
#if TARGET_CPU_X86
cpu = @"x86";
@@ -172,7 +171,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const {
if (cpu) {
[userAgentComponents addObject:[NSString stringWithFormat:@"(%@)", cpu]];
}
-
+
return [userAgentComponents componentsJoinedByString:@" "];
}
@@ -295,20 +294,20 @@ std::unique_ptr<AsyncRequest> HTTPFileSource::request(const Resource& resource,
response.error =
std::make_unique<Error>(Error::Reason::NotFound, "HTTP status code 404");
} else if (responseCode == 429) {
- //Get the standard header
+ // Get the standard header
optional<std::string> retryAfter;
NSString *retryAfterHeader = headers[@"Retry-After"];
if (retryAfterHeader) {
retryAfter = std::string([retryAfterHeader UTF8String]);
}
-
- //Fallback mapbox specific header
+
+ // Fallback mapbox specific header
optional<std::string> xRateLimitReset;
NSString *xReset = headers[@"x-rate-limit-reset"];
if (xReset) {
xRateLimitReset = std::string([xReset UTF8String]);
}
-
+
response.error = std::make_unique<Error>(Error::Reason::RateLimit, "HTTP status code 429", http::parseRetryHeaders(retryAfter, xRateLimitReset));
} else if (responseCode >= 500 && responseCode < 600) {
response.error =
diff --git a/platform/darwin/src/image.mm b/platform/darwin/src/image.mm
index 3a707d4a36..57b680fbdb 100644
--- a/platform/darwin/src/image.mm
+++ b/platform/darwin/src/image.mm
@@ -1,126 +1,107 @@
-#include <mbgl/util/image.hpp>
+#include <mbgl/util/image+MGLAdditions.hpp>
#import <ImageIO/ImageIO.h>
-#if TARGET_OS_IPHONE
-#import <MobileCoreServices/MobileCoreServices.h>
-#else
-#import <CoreServices/CoreServices.h>
-#endif
-
-namespace mbgl {
-
-std::string encodePNG(const PremultipliedImage& src) {
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, src.data.get(), src.bytes(), NULL);
+namespace {
+
+template <typename T, typename S, void (*Releaser)(S)>
+struct CFHandle {
+ CFHandle(T t_): t(t_) {}
+ ~CFHandle() { Releaser(t); }
+ T operator*() { return t; }
+ operator bool() { return t; }
+private:
+ T t;
+};
+
+} // namespace
+
+using CGImageHandle = CFHandle<CGImageRef, CGImageRef, CGImageRelease>;
+using CFDataHandle = CFHandle<CFDataRef, CFTypeRef, CFRelease>;
+using CGImageSourceHandle = CFHandle<CGImageSourceRef, CFTypeRef, CFRelease>;
+using CGDataProviderHandle = CFHandle<CGDataProviderRef, CGDataProviderRef, CGDataProviderRelease>;
+using CGColorSpaceHandle = CFHandle<CGColorSpaceRef, CGColorSpaceRef, CGColorSpaceRelease>;
+using CGContextHandle = CFHandle<CGContextRef, CGContextRef, CGContextRelease>;
+
+CGImageRef CGImageFromMGLPremultipliedImage(mbgl::PremultipliedImage&& src) {
+ // We're converting the PremultipliedImage's backing store to a CGDataProvider, and are taking
+ // over ownership of the memory.
+ CGDataProviderHandle provider(CGDataProviderCreateWithData(
+ NULL, src.data.get(), src.bytes(), [](void*, const void* data, size_t) {
+ delete[] reinterpret_cast<const decltype(src.data)::element_type*>(data);
+ }));
if (!provider) {
- return "";
+ return nil;
}
- CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
- if (!color_space) {
- CGDataProviderRelease(provider);
- return "";
- }
+ // If we successfully created the provider, it will take over management of the memory segment.
+ src.data.release();
- CGImageRef image =
- CGImageCreate(src.size.width, src.size.height, 8, 32, 4 * src.size.width, color_space,
- kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, provider, NULL,
- false, kCGRenderingIntentDefault);
- if (!image) {
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
+ CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB());
+ if (!colorSpace) {
+ return nil;
}
- CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
- if (!data) {
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
- }
+ constexpr const size_t bitsPerComponent = 8;
+ constexpr const size_t bytesPerPixel = 4;
+ constexpr const size_t bitsPerPixel = bitsPerComponent * bytesPerPixel;
+ const size_t bytesPerRow = bytesPerPixel * src.size.width;
- CGImageDestinationRef image_destination = CGImageDestinationCreateWithData(data, kUTTypePNG, 1, NULL);
- if (!image_destination) {
- CFRelease(data);
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
- return "";
+ return CGImageCreate(src.size.width, src.size.height, bitsPerComponent, bitsPerPixel,
+ bytesPerRow, *colorSpace,
+ kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, *provider,
+ NULL, false, kCGRenderingIntentDefault);
+}
+
+mbgl::PremultipliedImage MGLPremultipliedImageFromCGImage(CGImageRef src) {
+ const size_t width = CGImageGetWidth(src);
+ const size_t height = CGImageGetHeight(src);
+
+ mbgl::PremultipliedImage image({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
+
+ CGColorSpaceHandle colorSpace(CGColorSpaceCreateDeviceRGB());
+ if (!colorSpace) {
+ throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed");
}
- CGImageDestinationAddImage(image_destination, image, NULL);
- CGImageDestinationFinalize(image_destination);
+ constexpr const size_t bitsPerComponent = 8;
+ constexpr const size_t bytesPerPixel = 4;
+ const size_t bytesPerRow = bytesPerPixel * width;
- const std::string result {
- reinterpret_cast<const char *>(CFDataGetBytePtr(data)),
- static_cast<size_t>(CFDataGetLength(data))
- };
+ CGContextHandle context(CGBitmapContextCreate(
+ image.data.get(), width, height, bitsPerComponent, bytesPerRow, *colorSpace,
+ kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast));
+ if (!context) {
+ throw std::runtime_error("CGBitmapContextCreate failed");
+ }
- CFRelease(image_destination);
- CFRelease(data);
- CGImageRelease(image);
- CGColorSpaceRelease(color_space);
- CGDataProviderRelease(provider);
+ CGContextSetBlendMode(*context, kCGBlendModeCopy);
+ CGContextDrawImage(*context, CGRectMake(0, 0, width, height), src);
- return result;
+ return image;
}
-PremultipliedImage decodeImage(const std::string &source_data) {
- CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, reinterpret_cast<const unsigned char *>(source_data.data()), source_data.size(), kCFAllocatorNull);
+namespace mbgl {
+
+PremultipliedImage decodeImage(const std::string& source) {
+ CFDataHandle data(CFDataCreateWithBytesNoCopy(
+ kCFAllocatorDefault, reinterpret_cast<const unsigned char*>(source.data()), source.size(),
+ kCFAllocatorNull));
if (!data) {
throw std::runtime_error("CFDataCreateWithBytesNoCopy failed");
}
- CGImageSourceRef image_source = CGImageSourceCreateWithData(data, NULL);
- if (!image_source) {
- CFRelease(data);
+ CGImageSourceHandle imageSource(CGImageSourceCreateWithData(*data, NULL));
+ if (!imageSource) {
throw std::runtime_error("CGImageSourceCreateWithData failed");
}
- CGImageRef image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
+ CGImageHandle image(CGImageSourceCreateImageAtIndex(*imageSource, 0, NULL));
if (!image) {
- CFRelease(image_source);
- CFRelease(data);
throw std::runtime_error("CGImageSourceCreateImageAtIndex failed");
}
- CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB();
- if (!color_space) {
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
- throw std::runtime_error("CGColorSpaceCreateDeviceRGB failed");
- }
-
- PremultipliedImage result({ static_cast<uint32_t>(CGImageGetWidth(image)),
- static_cast<uint32_t>(CGImageGetHeight(image)) });
-
- CGContextRef context =
- CGBitmapContextCreate(result.data.get(), result.size.width, result.size.height, 8,
- result.stride(), color_space, kCGImageAlphaPremultipliedLast);
- if (!context) {
- CGColorSpaceRelease(color_space);
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
- throw std::runtime_error("CGBitmapContextCreate failed");
- }
-
- CGContextSetBlendMode(context, kCGBlendModeCopy);
-
- CGRect rect = { { 0, 0 },
- { static_cast<CGFloat>(result.size.width),
- static_cast<CGFloat>(result.size.height) } };
- CGContextDrawImage(context, rect, image);
-
- CGContextRelease(context);
- CGColorSpaceRelease(color_space);
- CGImageRelease(image);
- CFRelease(image_source);
- CFRelease(data);
-
- return result;
+ return MGLPremultipliedImageFromCGImage(*image);
}
-}
+} // namespace mbgl
diff --git a/platform/darwin/src/run_loop.cpp b/platform/darwin/src/run_loop.cpp
index 63bd8d2f53..bae8164ab6 100644
--- a/platform/darwin/src/run_loop.cpp
+++ b/platform/darwin/src/run_loop.cpp
@@ -7,7 +7,11 @@
namespace mbgl {
namespace util {
-static ThreadLocal<RunLoop>& current = *new ThreadLocal<RunLoop>;
+// Use a static function to avoid the static initialization order fiasco.
+static auto& current() {
+ static ThreadLocal<RunLoop> tl;
+ return tl;
+};
class RunLoop::Impl {
public:
@@ -15,19 +19,20 @@ public:
};
RunLoop* RunLoop::Get() {
- assert(current.get());
- return current.get();
+ assert(current().get());
+ return current().get();
}
RunLoop::RunLoop(Type)
: impl(std::make_unique<Impl>()) {
- assert(!current.get());
- current.set(this);
+ assert(!current().get());
+ current().set(this);
impl->async = std::make_unique<AsyncTask>(std::bind(&RunLoop::process, this));
}
RunLoop::~RunLoop() {
- current.set(nullptr);
+ assert(current().get());
+ current().set(nullptr);
}
void RunLoop::push(std::shared_ptr<WorkTask> task) {
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index 3cdb7adffb..74859bda82 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -16,7 +16,7 @@
@"CC&nbsp;BY-SA "
@"<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];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
@@ -24,25 +24,25 @@
linkColor:nil];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
-
+
XCTAssertEqual(infos.count, 4);
-
+
CLLocationCoordinate2D mapbox = CLLocationCoordinate2DMake(12.9810816, 77.6368034);
XCTAssertEqualObjects(infos[0].title.string, @"© Mapbox");
XCTAssertEqualObjects(infos[0].URL, [NSURL URLWithString:@"https://www.mapbox.com/about/maps/"]);
XCTAssertFalse(infos[0].feedbackLink);
XCTAssertNil([infos[0] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
-
+
XCTAssertEqualObjects(infos[1].title.string, @"©️ OpenStreetMap");
XCTAssertEqualObjects(infos[1].URL, [NSURL URLWithString:@"http://www.openstreetmap.org/about/"]);
XCTAssertFalse(infos[1].feedbackLink);
XCTAssertNil([infos[1] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
-
+
XCTAssertEqualObjects(infos[2].title.string, @"CC\u00a0BY-SA");
XCTAssertNil(infos[2].URL);
XCTAssertFalse(infos[2].feedbackLink);
XCTAssertNil([infos[2] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14]);
-
+
XCTAssertEqualObjects(infos[3].title.string, @"Improve this map");
XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://www.mapbox.com/map-feedback/"]);
XCTAssertTrue(infos[3].feedbackLink);
@@ -54,7 +54,7 @@
static NSString * const htmlStrings[] = {
@"<a href=\"https://www.mapbox.com/\">Mapbox</a>",
};
-
+
CGFloat fontSize = 72;
MGLColor *color = [MGLColor redColor];
NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
@@ -64,13 +64,13 @@
linkColor:color];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
-
+
XCTAssertEqual(infos.count, 1);
-
+
XCTAssertEqualObjects(infos[0].title.string, @"Mapbox");
XCTAssertEqualObjects([infos[0].title attribute:NSLinkAttributeName atIndex:0 effectiveRange:nil], [NSURL URLWithString:@"https://www.mapbox.com/"]);
XCTAssertEqualObjects([infos[0].title attribute:NSUnderlineStyleAttributeName atIndex:0 effectiveRange:nil], @(NSUnderlineStyleSingle));
-
+
#if TARGET_OS_IPHONE
UIFont *font;
#else
@@ -78,7 +78,7 @@
#endif
font = [infos[0].title attribute:NSFontAttributeName atIndex:0 effectiveRange:nil];
XCTAssertEqual(font.pointSize, fontSize);
-
+
CGFloat r, g, b, a;
[color getRed:&r green:&g blue:&b alpha:&a];
MGLColor *linkColor = [infos[0].title attribute:NSForegroundColorAttributeName atIndex:0 effectiveRange:nil];
@@ -98,7 +98,7 @@
@"Hello",
@"Hello World",
};
-
+
NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
@@ -106,7 +106,7 @@
linkColor:nil];
[infos growArrayByAddingAttributionInfosFromArray:subinfos];
}
-
+
XCTAssertEqual(infos.count, 2);
XCTAssertEqualObjects(infos[0].title.string, @"Hello World");
XCTAssertEqualObjects(infos[1].title.string, @"Another Source");
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
index 60a332a5e7..92c0ac7cbc 100644
--- a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
+++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -21,107 +21,122 @@
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::BackgroundLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::BackgroundLayer>();
-
+
// background-color
{
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"background-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.backgroundColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.backgroundColor = styleValue;
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.backgroundColor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
@"Setting backgroundColor to a constant value should update background-color.");
- XCTAssertEqualObjects(layer.backgroundColor, styleValue,
+ XCTAssertEqualObjects(layer.backgroundColor, constantStyleValue,
@"backgroundColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.backgroundColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.backgroundColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
- @"Setting backgroundColor to a function should update background-color.");
- XCTAssertEqualObjects(layer.backgroundColor, styleValue,
- @"backgroundColor should round-trip functions.");
-
+ @"Setting backgroundColor to a camera function should update background-color.");
+ XCTAssertEqualObjects(layer.backgroundColor, functionStyleValue,
+ @"backgroundColor should round-trip camera functions.");
+
+
+
layer.backgroundColor = nil;
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@"Unsetting backgroundColor should return background-color to the default value.");
XCTAssertEqualObjects(layer.backgroundColor, defaultStyleValue,
@"backgroundColor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundColor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// background-opacity
{
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"background-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.backgroundOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.backgroundOpacity = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.backgroundOpacity = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
@"Setting backgroundOpacity to a constant value should update background-opacity.");
- XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
+ XCTAssertEqualObjects(layer.backgroundOpacity, constantStyleValue,
@"backgroundOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.backgroundOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.backgroundOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
- @"Setting backgroundOpacity to a function should update background-opacity.");
- XCTAssertEqualObjects(layer.backgroundOpacity, styleValue,
- @"backgroundOpacity should round-trip functions.");
-
+ @"Setting backgroundOpacity to a camera function should update background-opacity.");
+ XCTAssertEqualObjects(layer.backgroundOpacity, functionStyleValue,
+ @"backgroundOpacity should round-trip camera functions.");
+
+
+
layer.backgroundOpacity = nil;
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@"Unsetting backgroundOpacity should return background-opacity to the default value.");
XCTAssertEqualObjects(layer.backgroundOpacity, defaultStyleValue,
@"backgroundOpacity should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// background-pattern
{
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"background-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.backgroundPattern;
-
- MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"];
- layer.backgroundPattern = styleValue;
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Background Pattern"];
+ layer.backgroundPattern = constantStyleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Background Pattern" };
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
@"Setting backgroundPattern to a constant value should update background-pattern.");
- XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
+ XCTAssertEqualObjects(layer.backgroundPattern, constantStyleValue,
@"backgroundPattern should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.backgroundPattern = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Background Pattern"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
- styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.backgroundPattern = styleValue;
- propertyValue = { mbgl::style::Function<std::string> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
- @"Setting backgroundPattern to a function should update background-pattern.");
- XCTAssertEqualObjects(layer.backgroundPattern, styleValue,
- @"backgroundPattern should round-trip functions.");
-
+ @"Setting backgroundPattern to a camera function should update background-pattern.");
+ XCTAssertEqualObjects(layer.backgroundPattern, functionStyleValue,
+ @"backgroundPattern should round-trip camera functions.");
+
+
+
layer.backgroundPattern = nil;
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
@"Unsetting backgroundPattern should return background-pattern to the default value.");
XCTAssertEqualObjects(layer.backgroundPattern, defaultStyleValue,
@"backgroundPattern should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.backgroundPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
index 35e29b31d5..d7515e8e4e 100644
--- a/platform/darwin/test/MGLCircleStyleLayerTests.mm
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -20,13 +20,13 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
-
+
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
@@ -37,356 +37,532 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::CircleLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::CircleLayer>();
-
+
// circle-blur
{
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"circle-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleBlur;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleBlur = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleBlur = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a constant value should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, styleValue,
+ XCTAssertEqualObjects(layer.circleBlur, constantStyleValue,
@"circleBlur should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleBlur = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleBlur = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
- @"Setting circleBlur to a function should update circle-blur.");
- XCTAssertEqualObjects(layer.circleBlur, styleValue,
- @"circleBlur should round-trip functions.");
-
+ @"Setting circleBlur to a camera function should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
+ @"circleBlur should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleBlur = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
+ @"Setting circleBlur to a source function should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
+ @"circleBlur should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleBlur = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
+ @"Setting circleBlur to a composite function should update circle-blur.");
+ XCTAssertEqualObjects(layer.circleBlur, functionStyleValue,
+ @"circleBlur should round-trip composite functions.");
+
+
layer.circleBlur = nil;
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@"Unsetting circleBlur should return circle-blur to the default value.");
XCTAssertEqualObjects(layer.circleBlur, defaultStyleValue,
@"circleBlur should return the default value after being unset.");
}
-
+
// circle-color
{
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"circle-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.circleColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.circleColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a constant value should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, styleValue,
+ XCTAssertEqualObjects(layer.circleColor, constantStyleValue,
@"circleColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
- @"Setting circleColor to a function should update circle-color.");
- XCTAssertEqualObjects(layer.circleColor, styleValue,
- @"circleColor should round-trip functions.");
-
+ @"Setting circleColor to a camera function should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
+ @"circleColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
+ @"Setting circleColor to a source function should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
+ @"circleColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
+ @"Setting circleColor to a composite function should update circle-color.");
+ XCTAssertEqualObjects(layer.circleColor, functionStyleValue,
+ @"circleColor should round-trip composite functions.");
+
+
layer.circleColor = nil;
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@"Unsetting circleColor should return circle-color to the default value.");
XCTAssertEqualObjects(layer.circleColor, defaultStyleValue,
@"circleColor should return the default value after being unset.");
}
-
+
// circle-opacity
{
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"circle-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a constant value should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, styleValue,
+ XCTAssertEqualObjects(layer.circleOpacity, constantStyleValue,
@"circleOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
- @"Setting circleOpacity to a function should update circle-opacity.");
- XCTAssertEqualObjects(layer.circleOpacity, styleValue,
- @"circleOpacity should round-trip functions.");
-
+ @"Setting circleOpacity to a camera function should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
+ @"circleOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
+ @"Setting circleOpacity to a source function should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
+ @"circleOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
+ @"Setting circleOpacity to a composite function should update circle-opacity.");
+ XCTAssertEqualObjects(layer.circleOpacity, functionStyleValue,
+ @"circleOpacity should round-trip composite functions.");
+
+
layer.circleOpacity = nil;
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@"Unsetting circleOpacity should return circle-opacity to the default value.");
XCTAssertEqualObjects(layer.circleOpacity, defaultStyleValue,
@"circleOpacity should return the default value after being unset.");
}
-
+
// circle-radius
{
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"circle-radius should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleRadius;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleRadius = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleRadius = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a constant value should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, styleValue,
+ XCTAssertEqualObjects(layer.circleRadius, constantStyleValue,
@"circleRadius should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleRadius = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleRadius = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
- @"Setting circleRadius to a function should update circle-radius.");
- XCTAssertEqualObjects(layer.circleRadius, styleValue,
- @"circleRadius should round-trip functions.");
-
+ @"Setting circleRadius to a camera function should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
+ @"circleRadius should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleRadius = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
+ @"Setting circleRadius to a source function should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
+ @"circleRadius should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleRadius = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
+ @"Setting circleRadius to a composite function should update circle-radius.");
+ XCTAssertEqualObjects(layer.circleRadius, functionStyleValue,
+ @"circleRadius should round-trip composite functions.");
+
+
layer.circleRadius = nil;
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@"Unsetting circleRadius should return circle-radius to the default value.");
XCTAssertEqualObjects(layer.circleRadius, defaultStyleValue,
@"circleRadius should return the default value after being unset.");
}
-
+
// circle-pitch-scale
{
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"circle-pitch-scale should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleScaleAlignment;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]];
- layer.circleScaleAlignment = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleScaleAlignment:MGLCircleScaleAlignmentViewport]];
+ layer.circleScaleAlignment = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::CirclePitchScaleType> propertyValue = { mbgl::style::CirclePitchScaleType::Viewport };
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
@"Setting circleScaleAlignment to a constant value should update circle-pitch-scale.");
- XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
+ XCTAssertEqualObjects(layer.circleScaleAlignment, constantStyleValue,
@"circleScaleAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleScaleAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::CirclePitchScaleType> intervalStops = { {{18, mbgl::style::CirclePitchScaleType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::CirclePitchScaleType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleScaleAlignment = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::CirclePitchScaleType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
- @"Setting circleScaleAlignment to a function should update circle-pitch-scale.");
- XCTAssertEqualObjects(layer.circleScaleAlignment, styleValue,
- @"circleScaleAlignment should round-trip functions.");
-
+ @"Setting circleScaleAlignment to a camera function should update circle-pitch-scale.");
+ XCTAssertEqualObjects(layer.circleScaleAlignment, functionStyleValue,
+ @"circleScaleAlignment should round-trip camera functions.");
+
+
+
layer.circleScaleAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@"Unsetting circleScaleAlignment should return circle-pitch-scale to the default value.");
XCTAssertEqualObjects(layer.circleScaleAlignment, defaultStyleValue,
@"circleScaleAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleScaleAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// circle-stroke-color
{
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"circle-stroke-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.circleStrokeColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.circleStrokeColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.circleStrokeColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a constant value should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
+ XCTAssertEqualObjects(layer.circleStrokeColor, constantStyleValue,
@"circleStrokeColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleStrokeColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleStrokeColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
- @"Setting circleStrokeColor to a function should update circle-stroke-color.");
- XCTAssertEqualObjects(layer.circleStrokeColor, styleValue,
- @"circleStrokeColor should round-trip functions.");
-
+ @"Setting circleStrokeColor to a camera function should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
+ @"circleStrokeColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleStrokeColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
+ @"Setting circleStrokeColor to a source function should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
+ @"circleStrokeColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleStrokeColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
+ @"Setting circleStrokeColor to a composite function should update circle-stroke-color.");
+ XCTAssertEqualObjects(layer.circleStrokeColor, functionStyleValue,
+ @"circleStrokeColor should round-trip composite functions.");
+
+
layer.circleStrokeColor = nil;
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@"Unsetting circleStrokeColor should return circle-stroke-color to the default value.");
XCTAssertEqualObjects(layer.circleStrokeColor, defaultStyleValue,
@"circleStrokeColor should return the default value after being unset.");
}
-
+
// circle-stroke-opacity
{
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"circle-stroke-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleStrokeOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleStrokeOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a constant value should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, constantStyleValue,
@"circleStrokeOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleStrokeOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleStrokeOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
- @"Setting circleStrokeOpacity to a function should update circle-stroke-opacity.");
- XCTAssertEqualObjects(layer.circleStrokeOpacity, styleValue,
- @"circleStrokeOpacity should round-trip functions.");
-
+ @"Setting circleStrokeOpacity to a camera function should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
+ @"circleStrokeOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleStrokeOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
+ @"Setting circleStrokeOpacity to a source function should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
+ @"circleStrokeOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleStrokeOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
+ @"Setting circleStrokeOpacity to a composite function should update circle-stroke-opacity.");
+ XCTAssertEqualObjects(layer.circleStrokeOpacity, functionStyleValue,
+ @"circleStrokeOpacity should round-trip composite functions.");
+
+
layer.circleStrokeOpacity = nil;
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@"Unsetting circleStrokeOpacity should return circle-stroke-opacity to the default value.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, defaultStyleValue,
@"circleStrokeOpacity should return the default value after being unset.");
}
-
+
// circle-stroke-width
{
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"circle-stroke-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.circleStrokeWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.circleStrokeWidth = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.circleStrokeWidth = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a constant value should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
+ XCTAssertEqualObjects(layer.circleStrokeWidth, constantStyleValue,
@"circleStrokeWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleStrokeWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleStrokeWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
- @"Setting circleStrokeWidth to a function should update circle-stroke-width.");
- XCTAssertEqualObjects(layer.circleStrokeWidth, styleValue,
- @"circleStrokeWidth should round-trip functions.");
-
+ @"Setting circleStrokeWidth to a camera function should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
+ @"circleStrokeWidth should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.circleStrokeWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
+ @"Setting circleStrokeWidth to a source function should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
+ @"circleStrokeWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.circleStrokeWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
+ @"Setting circleStrokeWidth to a composite function should update circle-stroke-width.");
+ XCTAssertEqualObjects(layer.circleStrokeWidth, functionStyleValue,
+ @"circleStrokeWidth should round-trip composite functions.");
+
+
layer.circleStrokeWidth = nil;
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@"Unsetting circleStrokeWidth should return circle-stroke-width to the default value.");
XCTAssertEqualObjects(layer.circleStrokeWidth, defaultStyleValue,
@"circleStrokeWidth should return the default value after being unset.");
}
-
+
// circle-translate
{
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"circle-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslation;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.circleTranslation = styleValue;
+ layer.circleTranslation = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
@"Setting circleTranslation to a constant value should update circle-translate.");
- XCTAssertEqualObjects(layer.circleTranslation, styleValue,
+ XCTAssertEqualObjects(layer.circleTranslation, constantStyleValue,
@"circleTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleTranslation = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
- @"Setting circleTranslation to a function should update circle-translate.");
- XCTAssertEqualObjects(layer.circleTranslation, styleValue,
- @"circleTranslation should round-trip functions.");
-
+ @"Setting circleTranslation to a camera function should update circle-translate.");
+ XCTAssertEqualObjects(layer.circleTranslation, functionStyleValue,
+ @"circleTranslation should round-trip camera functions.");
+
+
+
layer.circleTranslation = nil;
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@"Unsetting circleTranslation should return circle-translate to the default value.");
XCTAssertEqualObjects(layer.circleTranslation, defaultStyleValue,
@"circleTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// circle-translate-anchor
{
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"circle-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.circleTranslationAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]];
- layer.circleTranslationAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLCircleTranslationAnchor:MGLCircleTranslationAnchorViewport]];
+ layer.circleTranslationAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
@"Setting circleTranslationAnchor to a constant value should update circle-translate-anchor.");
- XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, constantStyleValue,
@"circleTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.circleTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.circleTranslationAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
- @"Setting circleTranslationAnchor to a function should update circle-translate-anchor.");
- XCTAssertEqualObjects(layer.circleTranslationAnchor, styleValue,
- @"circleTranslationAnchor should round-trip functions.");
-
+ @"Setting circleTranslationAnchor to a camera function should update circle-translate-anchor.");
+ XCTAssertEqualObjects(layer.circleTranslationAnchor, functionStyleValue,
+ @"circleTranslationAnchor should round-trip camera functions.");
+
+
+
layer.circleTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
@"Unsetting circleTranslationAnchor should return circle-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, defaultStyleValue,
@"circleTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.circleTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLClockDirectionFormatterTests.m b/platform/darwin/test/MGLClockDirectionFormatterTests.m
index a020ed88b2..13e12ae2f2 100644
--- a/platform/darwin/test/MGLClockDirectionFormatterTests.m
+++ b/platform/darwin/test/MGLClockDirectionFormatterTests.m
@@ -12,59 +12,59 @@ static NSString * const MGLTestLocaleIdentifier = @"en-US";
- (void)testClockDirections {
MGLClockDirectionFormatter *shortFormatter = [[MGLClockDirectionFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
-
+
MGLClockDirectionFormatter *mediumFormatter = [[MGLClockDirectionFormatter alloc] init];
-
+
MGLClockDirectionFormatter *longFormatter = [[MGLClockDirectionFormatter alloc] init];
longFormatter.unitStyle = NSFormattingUnitStyleLong;
-
+
CLLocationDirection direction;
-
+
direction = -90;
XCTAssertEqualObjects(@"9:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"9 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"9 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 0;
XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 45;
XCTAssertEqualObjects(@"2:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"2 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"2 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 90;
XCTAssertEqualObjects(@"3:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"3 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"3 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 180;
XCTAssertEqualObjects(@"6:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"6 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"6 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 270;
XCTAssertEqualObjects(@"9:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"9 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"9 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 359.34951805867024;
XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 360;
XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 360.1;
XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [longFormatter stringFromDirection:direction]);
-
+
direction = 720;
XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:direction]);
diff --git a/platform/darwin/test/MGLCodingTests.m b/platform/darwin/test/MGLCodingTests.m
index b9b299d50f..ff0d674ad1 100644
--- a/platform/darwin/test/MGLCodingTests.m
+++ b/platform/darwin/test/MGLCodingTests.m
@@ -19,11 +19,11 @@
annotation.coordinate = CLLocationCoordinate2DMake(0.5, 0.5);
annotation.title = @"title";
annotation.subtitle = @"subtitle";
-
+
NSString *filePath = [self temporaryFilePathForClass:MGLPointAnnotation.class];
[NSKeyedArchiver archiveRootObject:annotation toFile:filePath];
MGLPointAnnotation *unarchivedAnnotation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(annotation, unarchivedAnnotation);
}
@@ -33,11 +33,11 @@
pointFeature.subtitle = @"subtitle";
pointFeature.identifier = @(123);
pointFeature.attributes = @{@"bbox": @[@1, @2, @3, @4]};
-
+
NSString *filePath = [self temporaryFilePathForClass:MGLPointFeature.class];
[NSKeyedArchiver archiveRootObject:pointFeature toFile:filePath];
MGLPointFeature *unarchivedPointFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(pointFeature, unarchivedPointFeature);
}
@@ -46,25 +46,25 @@
CLLocationCoordinate2DMake(0.129631234123, 1.7812739312551),
CLLocationCoordinate2DMake(2.532083092342, 3.5216418292392)
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
polyline.title = @"title";
polyline.subtitle = @"subtitle";
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPolyline class]];
[NSKeyedArchiver archiveRootObject:polyline toFile:filePath];
MGLPolyline *unarchivedPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(polyline, unarchivedPolyline);
-
+
CLLocationCoordinate2D otherCoordinates[] = {
CLLocationCoordinate2DMake(-1, -2)
};
-
+
[unarchivedPolyline replaceCoordinatesInRange:NSMakeRange(0, 1) withCoordinates:otherCoordinates];
-
+
XCTAssertNotEqualObjects(polyline, unarchivedPolyline);
}
@@ -73,18 +73,18 @@
CLLocationCoordinate2DMake(0.664482398, 1.8865675),
CLLocationCoordinate2DMake(2.13224687, 3.9984632)
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
polygon.title = nil;
polygon.subtitle = @"subtitle";
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
-
+
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(polygon, unarchivedPolygon);
}
@@ -93,24 +93,24 @@
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
CLLocationCoordinate2D interiorCoordinates[] = {
CLLocationCoordinate2DMake(4, 4),
CLLocationCoordinate2DMake(6, 6)
};
-
+
NSUInteger numberOfInteriorCoordinates = sizeof(interiorCoordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPolygon *interiorPolygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:numberOfInteriorCoordinates];
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates interiorPolygons:@[interiorPolygon]];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygon class]];
[NSKeyedArchiver archiveRootObject:polygon toFile:filePath];
-
+
MGLPolygon *unarchivedPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(polygon, unarchivedPolygon);
}
@@ -119,21 +119,21 @@
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
polylineFeature.attributes = @{@"bbox": @[@0, @1, @2, @3]};
polylineFeature.identifier = @"identifier";
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:polylineFeature toFile:filePath];
-
+
MGLPolylineFeature *unarchivedPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(polylineFeature, unarchivedPolylineFeature);
-
+
unarchivedPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
-
+
XCTAssertNotEqualObjects(polylineFeature, unarchivedPolylineFeature);
}
@@ -142,19 +142,19 @@
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 20)
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPolygonFeature class]];
[NSKeyedArchiver archiveRootObject:polygonFeature toFile:filePath];
-
+
MGLPolygonFeature *unarchivedPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(polygonFeature, unarchivedPolygonFeature);
-
+
unarchivedPolygonFeature.identifier = @"test";
-
+
XCTAssertNotEqualObjects(polygonFeature, unarchivedPolygonFeature);
}
@@ -165,15 +165,15 @@
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPointCollection *pointCollection = [MGLPointCollection pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollection class]];
[NSKeyedArchiver archiveRootObject:pointCollection toFile:filePath];
-
+
MGLPointCollection *unarchivedPointCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(pointCollection, unarchivedPointCollection);
}
@@ -184,88 +184,88 @@
feature.coordinate = CLLocationCoordinate2DMake(arc4random() % 90, arc4random() % 180);
[features addObject:feature];
}
-
+
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPointCollectionFeature *collection = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:numberOfCoordinates];
collection.identifier = @"identifier";
collection.attributes = @{@"bbox": @[@1, @2, @3, @4]};
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLPointCollectionFeature class]];
[NSKeyedArchiver archiveRootObject:collection toFile:filePath];
-
+
MGLPointCollectionFeature *unarchivedCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(collection, unarchivedCollection);
-
+
unarchivedCollection.identifier = @"newIdentifier";
-
+
XCTAssertNotEqualObjects(collection, unarchivedCollection);
}
- (void)testMultiPolyline {
-
+
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
NSMutableArray *polylines = [NSMutableArray array];
-
+
for (NSUInteger i = 0; i < 100; i++) {
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
[polylines addObject:polyline];
}
-
+
MGLMultiPolyline *multiPolyline = [MGLMultiPolyline multiPolylineWithPolylines:polylines];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolyline class]];
[NSKeyedArchiver archiveRootObject:multiPolyline toFile:filePath];
-
+
MGLMultiPolyline *unarchivedMultiPolyline = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolyline *anotherMultipolyline = [MGLMultiPolyline multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
-
+
XCTAssertEqualObjects(multiPolyline, unarchivedMultiPolyline);
XCTAssertNotEqualObjects(unarchivedMultiPolyline, anotherMultipolyline);
}
- (void)testMultiPolygon {
-
+
CLLocationCoordinate2D coordinates[] = {
CLLocationCoordinate2DMake(0, 1),
CLLocationCoordinate2DMake(10, 11),
CLLocationCoordinate2DMake(20, 21),
CLLocationCoordinate2DMake(30, 31),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
NSMutableArray *polygons = [NSMutableArray array];
-
+
for (NSUInteger i = 0; i < 100; i++) {
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
[polygons addObject:polygon];
}
-
+
MGLMultiPolygon *multiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:polygons];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolygon class]];
[NSKeyedArchiver archiveRootObject:multiPolygon toFile:filePath];
-
+
MGLMultiPolygon *unarchivedMultiPolygon = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygon *anotherMultiPolygon = [MGLMultiPolygon multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
-
+
XCTAssertEqualObjects(multiPolygon, unarchivedMultiPolygon);
XCTAssertNotEqualObjects(anotherMultiPolygon, unarchivedMultiPolygon);
}
@@ -276,20 +276,20 @@
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:coordinates count:numberOfCoordinates];
-
+
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polyline, polygon]];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollection class]];
[NSKeyedArchiver archiveRootObject:shapeCollection toFile:filePath];
-
+
MGLShapeCollection *unarchivedShapeCollection = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLShapeCollection *anotherShapeCollection = [MGLShapeCollection shapeCollectionWithShapes:@[polygon]];
-
+
XCTAssertEqualObjects(shapeCollection, unarchivedShapeCollection);
XCTAssertNotEqualObjects(shapeCollection, anotherShapeCollection);
}
@@ -300,25 +300,25 @@
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
NSMutableArray *polylines = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++) {
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
polylineFeature.identifier = @(arc4random() % 100).stringValue;
[polylines addObject:polylineFeature];
}
-
+
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:polylines];
multiPolylineFeature.attributes = @{@"bbox": @[@4, @3, @2, @1]};
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:multiPolylineFeature toFile:filePath];
-
+
MGLMultiPolylineFeature *unarchivedMultiPolylineFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolylineFeature *anotherMultiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:[polylines subarrayWithRange:NSMakeRange(0, polylines.count/2)]];
-
+
XCTAssertEqualObjects(multiPolylineFeature, unarchivedMultiPolylineFeature);
XCTAssertNotEqualObjects(unarchivedMultiPolylineFeature, anotherMultiPolylineFeature);
}
@@ -329,28 +329,28 @@
CLLocationCoordinate2DMake(20.88471238, 21.93684215),
CLLocationCoordinate2DMake(30.15697236, 31.32988123),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
NSMutableArray *polygons = [NSMutableArray array];
for (NSUInteger i = 0; i < 100; i++ ) {
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
polygonFeature.identifier = @(arc4random_uniform(100)).stringValue;
[polygons addObject:polygonFeature];
}
-
+
MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:polygons];
multiPolygonFeature.attributes = @{@"bbox": @[@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100))]};
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLMultiPolylineFeature class]];
[NSKeyedArchiver archiveRootObject:multiPolygonFeature toFile:filePath];
-
+
MGLMultiPolygonFeature *unarchivedMultiPolygonFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
MGLMultiPolygonFeature *anotherMultiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:[polygons subarrayWithRange:NSMakeRange(0, polygons.count/2)]];
-
+
XCTAssertEqualObjects(multiPolygonFeature, unarchivedMultiPolygonFeature);
XCTAssertNotEqualObjects(anotherMultiPolygonFeature, unarchivedMultiPolygonFeature);
}
@@ -361,24 +361,24 @@
CLLocationCoordinate2DMake(20.91836515, 21.93689215),
CLLocationCoordinate2DMake(30.55697246, 31.33988123),
};
-
+
NSUInteger numberOfCoordinates = sizeof(coordinates) / sizeof(CLLocationCoordinate2D);
-
+
MGLPolylineFeature *polyline = [MGLPolylineFeature polylineWithCoordinates:coordinates count:numberOfCoordinates];
MGLPolygonFeature *polygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:numberOfCoordinates];
-
+
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polyline, polygon]];
shapeCollectionFeature.identifier = @(arc4random_uniform(100)).stringValue;
shapeCollectionFeature.attributes = @{@"bbox":@[@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100)),
@(arc4random_uniform(100))]};
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLShapeCollectionFeature class]];
[NSKeyedArchiver archiveRootObject:shapeCollectionFeature toFile:filePath];
-
+
MGLShapeCollectionFeature *unarchivedShapeCollectionFeature = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(shapeCollectionFeature, unarchivedShapeCollectionFeature);
}
@@ -395,14 +395,14 @@
[[NSColor redColor] drawSwatchInRect:CGRectMake(0, 0, 10, 10)];
[image unlockFocus];
#endif
-
+
MGLAnnotationImage *annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:@(arc4random_uniform(100)).stringValue];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationImage class]];
[NSKeyedArchiver archiveRootObject:annotationImage toFile:filePath];
-
+
MGLAnnotationImage *unarchivedAnnotationImage = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(annotationImage, unarchivedAnnotationImage);
}
@@ -414,12 +414,12 @@
annotationView.draggable = YES;
annotationView.centerOffset = CGVectorMake(10, 10);
annotationView.scalesWithViewingDistance = NO;
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLAnnotationView class]];
[NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
-
+
MGLAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
@@ -432,12 +432,12 @@
- (void)testUserLocation {
MGLUserLocation *userLocation = [[MGLUserLocation alloc] init];
userLocation.location = [[CLLocation alloc] initWithLatitude:1 longitude:1];
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocation class]];
[NSKeyedArchiver archiveRootObject:userLocation toFile:filePath];
-
+
MGLUserLocation *unarchivedUserLocation = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqualObjects(userLocation, unarchivedUserLocation);
unarchivedUserLocation.location = [[CLLocation alloc] initWithLatitude:10 longitude:10];
XCTAssertNotEqualObjects(userLocation, unarchivedUserLocation);
@@ -452,12 +452,12 @@
annotationView.draggable = YES;
annotationView.centerOffset = CGVectorMake(10, 10);
annotationView.scalesWithViewingDistance = NO;
-
+
NSString *filePath = [self temporaryFilePathForClass:[MGLUserLocationAnnotationView class]];
[NSKeyedArchiver archiveRootObject:annotationView toFile:filePath];
-
+
MGLUserLocationAnnotationView *unarchivedAnnotationView = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
-
+
XCTAssertEqual(annotationView.enabled, unarchivedAnnotationView.enabled);
XCTAssertEqual(annotationView.selected, unarchivedAnnotationView.selected);
XCTAssertEqual(annotationView.draggable, unarchivedAnnotationView.draggable);
diff --git a/platform/darwin/test/MGLCompassDirectionFormatterTests.m b/platform/darwin/test/MGLCompassDirectionFormatterTests.m
index bba0317ebf..c4ccc6ac4f 100644
--- a/platform/darwin/test/MGLCompassDirectionFormatterTests.m
+++ b/platform/darwin/test/MGLCompassDirectionFormatterTests.m
@@ -10,75 +10,75 @@
- (void)testCompassDirections {
MGLCompassDirectionFormatter *shortFormatter = [[MGLCompassDirectionFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
-
+
MGLCompassDirectionFormatter *mediumFormatter = [[MGLCompassDirectionFormatter alloc] init];
XCTAssertEqual(mediumFormatter.unitStyle, NSFormattingUnitStyleMedium, @"Unit style should be medium by default.");
-
+
MGLCompassDirectionFormatter *longFormatter = [[MGLCompassDirectionFormatter alloc] init];
longFormatter.unitStyle = NSFormattingUnitStyleLong;
-
+
CLLocationDirection direction;
-
+
direction = -45;
XCTAssertEqualObjects(@"NW", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"northwest", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"northwest", [longFormatter stringFromDirection:direction]);
-
+
direction = 0;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [longFormatter stringFromDirection:direction]);
-
+
direction = 1;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [longFormatter stringFromDirection:direction]);
-
+
direction = 10;
XCTAssertEqualObjects(@"NbE", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north by east", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north by east", [longFormatter stringFromDirection:direction]);
-
+
direction = 20;
XCTAssertEqualObjects(@"NNE", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north-northeast", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north-northeast", [longFormatter stringFromDirection:direction]);
-
+
direction = 45;
XCTAssertEqualObjects(@"NE", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"northeast", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"northeast", [longFormatter stringFromDirection:direction]);
-
+
direction = 90;
XCTAssertEqualObjects(@"E", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"east", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"east", [longFormatter stringFromDirection:direction]);
-
+
direction = 180;
XCTAssertEqualObjects(@"S", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"south", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"south", [longFormatter stringFromDirection:direction]);
-
+
direction = 270;
XCTAssertEqualObjects(@"W", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"west", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"west", [longFormatter stringFromDirection:direction]);
-
+
direction = 359.34951805867024;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [longFormatter stringFromDirection:direction]);
-
+
direction = 360;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [longFormatter stringFromDirection:direction]);
-
+
direction = 360.1;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [longFormatter stringFromDirection:direction]);
-
+
direction = 720;
XCTAssertEqualObjects(@"N", [shortFormatter stringFromDirection:direction]);
XCTAssertEqualObjects(@"north", [mediumFormatter stringFromDirection:direction]);
diff --git a/platform/darwin/test/MGLCoordinateFormatterTests.m b/platform/darwin/test/MGLCoordinateFormatterTests.m
index 6a6c7a3b2e..ac083fa103 100644
--- a/platform/darwin/test/MGLCoordinateFormatterTests.m
+++ b/platform/darwin/test/MGLCoordinateFormatterTests.m
@@ -12,33 +12,33 @@
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
XCTAssertTrue(shortFormatter.allowsSeconds, @"Arcseconds should be allowed by default.");
XCTAssertTrue(shortFormatter.allowsMinutes, @"Arcminutes should be allowed by default.");
-
+
MGLCoordinateFormatter *mediumFormatter = [[MGLCoordinateFormatter alloc] init];
XCTAssertEqual(mediumFormatter.unitStyle, NSFormattingUnitStyleMedium, @"Unit style should be medium by default.");
-
+
MGLCoordinateFormatter *longFormatter = [[MGLCoordinateFormatter alloc] init];
longFormatter.unitStyle = NSFormattingUnitStyleLong;
-
+
CLLocationCoordinate2D coordinate;
-
+
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");
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;
longFormatter.allowsSeconds = NO;
-
+
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");
XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
-
+
shortFormatter.allowsMinutes = NO;
mediumFormatter.allowsMinutes = NO;
longFormatter.allowsMinutes = NO;
-
+
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"39°N, 77°W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"39° north, 77° west");
diff --git a/platform/darwin/test/MGLDistanceFormatterTests.m b/platform/darwin/test/MGLDistanceFormatterTests.m
new file mode 100644
index 0000000000..f15ad9d313
--- /dev/null
+++ b/platform/darwin/test/MGLDistanceFormatterTests.m
@@ -0,0 +1,30 @@
+#import <Mapbox/Mapbox.h>
+#import <XCTest/XCTest.h>
+
+@interface MGLDistanceFormatterTests : XCTestCase
+
+@end
+
+@implementation MGLDistanceFormatterTests
+
+- (void)testAbbreviatedMetricUnits {
+ MGLDistanceFormatter *formatter = [[MGLDistanceFormatter alloc] init];
+ formatter.numberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_CA"];
+ for (CLLocationDistance distance=0; distance <= 10000; distance+=5) {
+ NSString *unit = [[formatter stringFromDistance:distance] componentsSeparatedByString:@" "][1];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", @[@"mm", @"cm", @"m", @"km"]];
+ XCTAssert([predicate evaluateWithObject:unit], @"Should only contain metric units");
+ }
+}
+
+- (void)testAbbreviatedImperialUnits {
+ MGLDistanceFormatter *formatter = [[MGLDistanceFormatter alloc] init];
+ formatter.numberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"];
+ for (CLLocationDistance distance=0; distance <= 10000; distance+=5) {
+ NSString *unit = [[formatter stringFromDistance:distance] componentsSeparatedByString:@" "][1];
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@", @[@"ft", @"mi"]];
+ XCTAssert([predicate evaluateWithObject:unit], @"Should only contain imperial units");
+ }
+}
+
+@end
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index d796b4e708..177d97d523 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -112,10 +112,10 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
layer.sourceLayerIdentifier = "population"
layer.circleColor = MGLStyleValue(rawValue: .green)
- layer.circleRadius = MGLStyleValue(interpolationBase: 1.75, stops: [
- 12: MGLStyleValue(rawValue: 2),
- 22: MGLStyleValue(rawValue: 180)
- ])
+ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: [12: MGLStyleValue(rawValue: 2),
+ 22: MGLStyleValue(rawValue: 180)],
+ options: [.interpolationBase: 1.75])
layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
mapView.style?.addLayer(layer)
@@ -131,10 +131,10 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
//#-example-code
let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = MGLStyleValue(interpolationBase: 1.5, stops: [
- 14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 20),
- ])
+ layer.lineWidth = MGLStyleValue(interpolationMode: .exponential,
+ cameraStops: [14: MGLStyleValue(rawValue: 2),
+ 18: MGLStyleValue(rawValue: 20)],
+ options: [.interpolationBase: 1.5])
layer.lineColor = MGLStyleValue(rawValue: .brown)
layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
@@ -217,4 +217,25 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.layer(withIdentifier: "contour"))
}
+
+ func testMGLMapView() {
+ //#-example-code
+ #if os(macOS)
+ class MapClickGestureRecognizer: NSClickGestureRecognizer {
+ override func shouldRequireFailure(of otherGestureRecognizer: NSGestureRecognizer) -> Bool {
+ return otherGestureRecognizer is NSClickGestureRecognizer
+ }
+ }
+ #else
+ let mapTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(myCustomFunction))
+ for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
+ mapTapGestureRecognizer.require(toFail: recognizer)
+ }
+ mapView.addGestureRecognizer(mapTapGestureRecognizer)
+ #endif
+ //#-end-example-code
+ }
+
+ // For testMGLMapView().
+ func myCustomFunction() {}
}
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 00b57c15f0..ad0833a068 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -2,8 +2,29 @@
#import <string>
+#import "MGLTypes.h"
#import "NSExpression+MGLAdditions.h"
+#define MGLAssertEqualValues(actual, expected, ...) \
+ XCTAssertTrue(actual.is<__typeof__(expected)>()); \
+ if (actual.is<__typeof__(expected)>()) { \
+ XCTAssertEqual(actual.get<__typeof__(expected)>(), expected, __VA_ARGS__); \
+ }
+
+#define MGLAssertEqualValuesWithAccuracy(actual, expected, accuracy, ...) \
+ XCTAssertTrue(actual.is<__typeof__(expected)>()); \
+ if (actual.is<__typeof__(expected)>()) { \
+ XCTAssertEqualWithAccuracy(actual.get<__typeof__(expected)>(), expected, accuracy, __VA_ARGS__); \
+ }
+
+#define MGLAssertConstantEqualsValue(constant, value, ...) \
+ MGLAssertEqualValues([NSExpression expressionForConstantValue:constant].mgl_constantMBGLValue, value, __VA_ARGS__);
+
+#define MGLAssertConstantEqualsValueWithAccuracy(constant, value, accuracy, ...) \
+ MGLAssertEqualValuesWithAccuracy([NSExpression expressionForConstantValue:constant].mgl_constantMBGLValue, value, accuracy, __VA_ARGS__);
+
+using namespace std::string_literals;
+
@interface MGLExpressionTests : XCTestCase
@end
@@ -23,193 +44,100 @@
return predicate;
}
-#pragma mark - String Tests
+#pragma mark - Valuation tests
-- (void)testExpressionConversionString
-{
- NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"bar"];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<std::string>());
- XCTAssertEqualObjects(@(convertedValue.get<std::string>().c_str()), @"bar");
+- (void)testStringValuation {
+ MGLAssertConstantEqualsValue(@"bar", "bar"s, @"NSString should convert to std::string.");
+ MGLAssertConstantEqualsValue(@"🆔🆗🇦🇶", "🆔🆗🇦🇶"s, @"NSString with non-ASCII characters should convert losslessly to std::string.");
}
-- (void)testExpressionConversionStringWithUnicode
-{
- NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@"🆔🆗🇦🇶"];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<std::string>());
- XCTAssertEqual(convertedValue.get<std::string>(), "🆔🆗🇦🇶");
+- (void)testColorValuation {
+ MGLAssertConstantEqualsValue([MGLColor redColor], "rgba(255,0,0,1)"s, @"MGLColor should convert to std::string containing CSS color string.");
}
-#pragma mark - Boolean Tests
-
-- (void)testExpressionConversionBooleanTrue
-{
- NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@YES];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<bool>());
- XCTAssertEqual(convertedValue.get<bool>(), true);
+- (void)testBooleanValuation {
+ MGLAssertConstantEqualsValue(@NO, false, @"Boolean NSNumber should convert to bool.");
+ MGLAssertConstantEqualsValue(@YES, true, @"Boolean NSNumber should convert to bool.");
}
-- (void)testExpressionConversionBooleanFalse
-{
- NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:@NO];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<bool>());
- XCTAssertEqual(convertedValue.get<bool>(), false);
-}
-
-#pragma mark - Floating Point Tests
-
-- (void)testExpressionConversionDouble
+- (void)testDoubleValuation
{
- NSComparisonPredicate *predicate;
- mbgl::Value convertedValue;
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MIN]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqual(convertedValue.get<double>(), DBL_MIN);
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithDouble:DBL_MAX]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqual(convertedValue.get<double>(), DBL_MAX);
+ MGLAssertConstantEqualsValue(@DBL_MIN, DBL_MIN, @"Double NSNumber should convert to double.");
+ MGLAssertConstantEqualsValue(@DBL_MAX, DBL_MAX, @"Double NSNumber should convert to double.");
}
-- (void)testExpressionConversionFloat
-{
+- (void)testFloatValuation {
// Because we can't guarantee precision when using float, and because
// we warn the user to this effect in -[NSExpression mgl_constantMBGLValue],
// we just check that things are in the ballpark here with integer values
// and some lower-precision checks.
-
- NSComparisonPredicate *predicate;
- mbgl::Value convertedValue;
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-1]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqual(convertedValue.get<double>(), -1);
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:1]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqual(convertedValue.get<double>(), 1);
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:-23.232342]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqualWithAccuracy(convertedValue.get<double>(), -23.232342, 0.000001);
-
- predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNumber numberWithFloat:23.232342]];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<double>());
- XCTAssertEqualWithAccuracy(convertedValue.get<double>(), 23.232342, 0.000001);
+
+ MGLAssertConstantEqualsValue(@-1.0f, -1.0, @"Float NSNumber should convert to double.");
+ MGLAssertConstantEqualsValue(@1.0f, 1.0, @"Float NSNumber should convert to double.");
+ MGLAssertConstantEqualsValueWithAccuracy(@-23.232342f, -23.232342, 0.000001, @"Float NSNumber should convert to double.");
+ MGLAssertConstantEqualsValueWithAccuracy(@23.232342f, 23.232342, 0.000001, @"Float NSNumber should convert to double.");
+ MGLAssertConstantEqualsValueWithAccuracy(@-FLT_MAX, static_cast<double>(-FLT_MAX), 0.000001, @"Float NSNumber should convert to double.");
+ MGLAssertConstantEqualsValueWithAccuracy(@FLT_MAX, static_cast<double>(FLT_MAX), 0.000001, @"Float NSNumber should convert to double.");
}
-#pragma mark - Integer Tests
-
-- (void)testExpressionNegativeIntegers
-{
- NSComparisonPredicate *predicate;
- mbgl::Value convertedValue;
-
- NSArray<NSNumber *> *minValues = @[
- [NSNumber numberWithShort: SHRT_MIN],
- [NSNumber numberWithInt: INT_MIN],
- [NSNumber numberWithLong: LONG_MIN],
- [NSNumber numberWithLongLong: LLONG_MIN],
- [NSNumber numberWithInteger: NSIntegerMin]
- ];
-
- NSArray<NSNumber *> *maxValues = @[
- [NSNumber numberWithShort: SHRT_MAX],
- [NSNumber numberWithInt: INT_MAX],
- [NSNumber numberWithLong: LONG_MAX],
- [NSNumber numberWithLongLong: LLONG_MAX],
- [NSNumber numberWithInteger: NSIntegerMax]
- ];
-
+- (void)testIntegerValuation {
// Negative integers should always come back as int64_t per mbgl::Value definition.
- // We use the long long value because it can store the highest number on both 32-
- // and 64-bit and won't overflow.
-
- for (NSNumber *min in minValues)
- {
- predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<int64_t>());
- XCTAssertEqual(convertedValue.get<int64_t>(), min.longLongValue);
- }
+ MGLAssertConstantEqualsValue(@SHRT_MIN, static_cast<int64_t>(SHRT_MIN), @"Negative short NSNumber should convert to int64_t.");
+ MGLAssertConstantEqualsValue(@INT_MIN, static_cast<int64_t>(INT_MIN), @"Negative int NSNumber should convert to int64_t.");
+ MGLAssertConstantEqualsValue(@LONG_MIN, static_cast<int64_t>(LONG_MIN), @"Negative long NSNumber should convert to int64_t.");
+ MGLAssertConstantEqualsValue(@LLONG_MIN, static_cast<int64_t>(LLONG_MIN), @"Negative long long NSNumber should convert to int64_t.");
+ MGLAssertConstantEqualsValue(@NSIntegerMin, static_cast<int64_t>(NSIntegerMin), @"Negative NSInteger NSNumber should convert to int64_t.");
// Positive integers should always come back as uint64_t per mbgl::Value definition.
- // We use the unsigned long long value because it can store the highest number on
- // both 32- and 64-bit and won't overflow.
-
- for (NSNumber *max in maxValues)
- {
- predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<uint64_t>());
- XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
- }
-
+ MGLAssertConstantEqualsValue(@SHRT_MAX, static_cast<uint64_t>(SHRT_MAX), @"Positive short NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@INT_MAX, static_cast<uint64_t>(INT_MAX), @"Positive int NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@LONG_MAX, static_cast<uint64_t>(LONG_MAX), @"Positive long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@LLONG_MAX, static_cast<uint64_t>(LLONG_MAX), @"Positive long long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@NSIntegerMax, static_cast<uint64_t>(NSIntegerMax), @"Positive NSInteger NSNumber should convert to uint64_t.");
}
-- (void)testExpressionPositiveAndZeroIntegers
-{
- NSComparisonPredicate *predicate;
- mbgl::Value convertedValue;
-
- NSArray<NSNumber *> *minValues = @[
- [NSNumber numberWithUnsignedShort: 0],
- [NSNumber numberWithUnsignedInt: 0],
- [NSNumber numberWithUnsignedLong: 0],
- [NSNumber numberWithUnsignedLongLong: 0],
- [NSNumber numberWithUnsignedInteger: 0]
- ];
-
- NSArray<NSNumber *> *maxValues = @[
- [NSNumber numberWithUnsignedShort: USHRT_MAX],
- [NSNumber numberWithUnsignedInt: UINT_MAX],
- [NSNumber numberWithUnsignedLong: ULONG_MAX],
- [NSNumber numberWithUnsignedLongLong: ULLONG_MAX],
- [NSNumber numberWithUnsignedInteger: NSUIntegerMax]
- ];
-
+- (void)testUnsignedIntegerValuation {
// Zero-value integers should always come back as uint64_t per mbgl::Value definition
// (using the interpretation that zero is not negative). We use the unsigned long long
// value just for parity with the positive integer test.
-
- for (NSNumber *min in minValues)
- {
- predicate = [self equalityComparisonPredicateWithRightConstantValue:min];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<uint64_t>());
- XCTAssertEqual(convertedValue.get<uint64_t>(), min.unsignedLongLongValue);
- }
+ MGLAssertConstantEqualsValue(@(static_cast<unsigned short>(0)), static_cast<uint64_t>(0), @"Unsigned short NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@0u, static_cast<uint64_t>(0), @"Unsigned int NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@0UL, static_cast<uint64_t>(0), @"Unsigned long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@0ULL, static_cast<uint64_t>(0), @"Unsigned long long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@(static_cast<NSUInteger>(0)), static_cast<uint64_t>(0), @"Unsigned NSUInteger NSNumber should convert to uint64_t.");
// Positive integers should always come back as uint64_t per mbgl::Value definition.
// We use the unsigned long long value because it can store the highest number on
// both 32- and 64-bit and won't overflow.
-
- for (NSNumber *max in maxValues)
- {
- predicate = [self equalityComparisonPredicateWithRightConstantValue:max];
- convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<uint64_t>());
- XCTAssertEqual(convertedValue.get<uint64_t>(), max.unsignedLongLongValue);
- }
+ MGLAssertConstantEqualsValue(@USHRT_MAX, static_cast<uint64_t>(USHRT_MAX), @"Unsigned short NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@UINT_MAX, static_cast<uint64_t>(UINT_MAX), @"Unsigned int NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@ULONG_MAX, static_cast<uint64_t>(ULONG_MAX), @"Unsigned long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@ULLONG_MAX, static_cast<uint64_t>(ULLONG_MAX), @"Unsigned long long NSNumber should convert to uint64_t.");
+ MGLAssertConstantEqualsValue(@NSUIntegerMax, static_cast<uint64_t>(NSUIntegerMax), @"Unsigned NSUInteger NSNumber should convert to uint64_t.");
}
-#pragma mark - Null Tests
+- (void)testNullValuation {
+ mbgl::NullValue nullValue;
+ MGLAssertConstantEqualsValue([NSNull null], nullValue, @"NSNull should convert to mbgl::NullValue.");
+}
-- (void)testExpressionConversionNull
-{
- NSComparisonPredicate *predicate = [self equalityComparisonPredicateWithRightConstantValue:[NSNull null]];
- mbgl::Value convertedValue = predicate.rightExpression.mgl_constantMBGLValue;
- XCTAssertTrue(convertedValue.is<mbgl::NullValue>());
+#pragma mark - Feature type tests
+
+- (void)testFeatureType {
+ XCTAssertEqual([NSExpression expressionForConstantValue:@"Point"].mgl_featureType, mbgl::FeatureType::Point);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@"LineString"].mgl_featureType, mbgl::FeatureType::LineString);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@"Polygon"].mgl_featureType, mbgl::FeatureType::Polygon);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@"Unknown"].mgl_featureType, mbgl::FeatureType::Unknown);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@""].mgl_featureType, mbgl::FeatureType::Unknown);
+
+ XCTAssertEqual([NSExpression expressionForConstantValue:@1].mgl_featureType, mbgl::FeatureType::Point);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@2].mgl_featureType, mbgl::FeatureType::LineString);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@3].mgl_featureType, mbgl::FeatureType::Polygon);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@0].mgl_featureType, mbgl::FeatureType::Unknown);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@-1].mgl_featureType, mbgl::FeatureType::Unknown);
+ XCTAssertEqual([NSExpression expressionForConstantValue:@4].mgl_featureType, mbgl::FeatureType::Unknown);
+
+ XCTAssertEqual([NSExpression expressionForConstantValue:nil].mgl_featureType, mbgl::FeatureType::Unknown);
}
@end
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index 91ec9d429e..818ad8200e 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -12,16 +12,16 @@
- (void)testGeometryConversion {
std::vector<mbgl::Feature> features;
-
+
mbgl::Point<double> point = { -90.066667, 29.95 };
features.push_back(mbgl::Feature { point });
-
+
mbgl::LineString<double> lineString = {
{ -84.516667, 39.1 },
{ -90.066667, 29.95 },
};
features.push_back(mbgl::Feature { lineString });
-
+
mbgl::Polygon<double> polygon = {
{
{ 1, 1 },
@@ -37,15 +37,15 @@
},
};
features.push_back(mbgl::Feature { polygon });
-
+
NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
-
+
MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0];
XCTAssertTrue([pointShape isKindOfClass:[MGLPointFeature class]]);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:pointShape.coordinate],
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]);
-
+
MGLPolylineFeature *polylineShape = (MGLPolylineFeature *)shapes[1];
XCTAssertTrue([polylineShape isKindOfClass:[MGLPolylineFeature class]]);
XCTAssertEqual(polylineShape.pointCount, 2);
@@ -55,7 +55,7 @@
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(39.1, -84.516667)]);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polylineCoordinates[1]],
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(29.95, -90.066667)]);
-
+
MGLPolygonFeature *polygonShape = (MGLPolygonFeature *)shapes[2];
XCTAssertTrue([polygonShape isKindOfClass:[MGLPolygonFeature class]]);
XCTAssertEqual(polygonShape.pointCount, 4);
@@ -87,7 +87,7 @@
- (void)testPropertyConversion {
std::vector<mbgl::Feature> features;
-
+
mbgl::Point<double> point = { -90.066667, 29.95 };
mbgl::Feature pointFeature { point };
pointFeature.id = { UINT64_MAX };
@@ -102,23 +102,23 @@
vector.push_back(false);
vector.push_back(true);
features.push_back(pointFeature);
-
+
NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes");
-
+
MGLShape <MGLFeature> *shape = shapes.firstObject;
XCTAssertTrue([shape conformsToProtocol:@protocol(MGLFeature)]);
XCTAssertTrue([shape isKindOfClass:[MGLShape class]]);
-
+
NSNumber *identifier = shape.identifier;
XCTAssertTrue([identifier isKindOfClass:[NSNumber class]], @"Feature identifier should be NSNumber");
XCTAssertEqual(strcmp(identifier.objCType, @encode(uint64_t)), 0, @"Feature identifier should be 64-bit unsigned integer");
-
+
NSNull *null = [shape attributeForKey:@"null"];
XCTAssertNotNil(null);
XCTAssertTrue([null isKindOfClass:[NSNull class]]);
XCTAssertEqual(null, shape.attributes[@"null"]);
-
+
NSNumber *boolean = [shape attributeForKey:@"bool"];
XCTAssertNotNil(boolean);
XCTAssertTrue([boolean isKindOfClass:[NSNumber class]]);
@@ -129,28 +129,28 @@
#endif
XCTAssertTrue(boolean.boolValue);
XCTAssertEqual(boolean, shape.attributes[@"bool"]);
-
+
NSNumber *unsignedInteger = [shape attributeForKey:@"unsigned int"];
XCTAssertNotNil(unsignedInteger);
XCTAssertTrue([unsignedInteger isKindOfClass:[NSNumber class]]);
XCTAssertEqual(strcmp(unsignedInteger.objCType, @encode(uint64_t)), 0, @"Unsigned integer property should be converted to unsigned long long NSNumber");
XCTAssertEqual(unsignedInteger.unsignedLongLongValue, UINT64_MAX);
XCTAssertEqual(unsignedInteger, shape.attributes[@"unsigned int"]);
-
+
NSNumber *integer = [shape attributeForKey:@"int"];
XCTAssertNotNil(integer);
XCTAssertTrue([integer isKindOfClass:[NSNumber class]]);
XCTAssertEqual(strcmp(integer.objCType, @encode(int64_t)), 0, @"Integer property should be converted to long long NSNumber");
XCTAssertEqual(integer.longLongValue, INT64_MIN);
XCTAssertEqual(integer, shape.attributes[@"int"]);
-
+
NSNumber *floatingPointNumber = [shape attributeForKey:@"double"];
XCTAssertNotNil(floatingPointNumber);
XCTAssertTrue([floatingPointNumber isKindOfClass:[NSNumber class]]);
XCTAssertEqual(strcmp(floatingPointNumber.objCType, @encode(double)), 0, @"Floating-point number property should be converted to double NSNumber");
XCTAssertEqual(floatingPointNumber.doubleValue, DBL_MAX);
XCTAssertEqual(floatingPointNumber, shape.attributes[@"double"]);
-
+
NSString *string = [shape attributeForKey:@"string"];
XCTAssertNotNil(string);
XCTAssertTrue([string isKindOfClass:[NSString class]]);
@@ -162,11 +162,11 @@
MGLPointFeature *pointFeature = [[MGLPointFeature alloc] init];
CLLocationCoordinate2D coordinate = { 10, 10 };
pointFeature.coordinate = coordinate;
-
+
// A GeoJSON feature
// when there are no identifier or properties
NSDictionary *geoJSONFeature = [pointFeature geoJSONDictionary];
-
+
// it has the correct type
XCTAssertEqualObjects(geoJSONFeature[@"type"], @"Feature");
// it has the correct geometry
@@ -177,17 +177,17 @@
XCTAssertNil(geoJSONFeature[@"id"]);
// it has a null representation of the properties object
XCTAssertEqualObjects(geoJSONFeature[@"properties"], [NSNull null]);
-
+
// when there is a string identifier
pointFeature.identifier = @"string-id";
-
+
// it has the identifier in the result
geoJSONFeature = [pointFeature geoJSONDictionary];
XCTAssertEqualObjects(geoJSONFeature[@"id"], pointFeature.identifier);
-
+
// when there are properties
pointFeature.attributes = @{@"name": @"name-value"};
-
+
// it has the properties value in the result
geoJSONFeature = [pointFeature geoJSONDictionary];
XCTAssertEqualObjects(geoJSONFeature[@"properties"], pointFeature.attributes);
@@ -198,10 +198,10 @@
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coords[] = { coord1, coord2 };
MGLPolylineFeature *polyLineFeature = [MGLPolylineFeature polylineWithCoordinates:coords count:2];
-
+
// A GeoJSON feature
NSDictionary *geoJSONFeature = [polyLineFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"LineString",
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
@@ -215,10 +215,10 @@
CLLocationCoordinate2D coord3 = { 0, 0 };
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coords count:3];
-
+
// A GeoJSON feature
NSDictionary *geoJSONFeature = [polygonFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"Polygon",
@"coordinates": @[@[@[@(coord1.longitude), @(coord1.latitude)],
@@ -232,15 +232,15 @@
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coord3 = { 0, 0 };
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
-
+
MGLPolyline *polyLine1 = [MGLPolyline polylineWithCoordinates:coords count:3];
MGLPolyline *polyLine2 = [MGLPolyline polylineWithCoordinates:coords count:3];
-
+
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[polyLine1, polyLine2]];
-
+
// A GeoJSON feature
NSDictionary *geoJSONFeature = [multiPolylineFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"MultiLineString",
@"coordinates": @[@[@[@(coord1.longitude), @(coord1.latitude)],
@@ -257,15 +257,15 @@
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coord3 = { 0, 0 };
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
-
+
MGLPolygon *polygon1 = [MGLPolygon polygonWithCoordinates:coords count:3];
MGLPolygon *polygon2 = [MGLPolygon polygonWithCoordinates:coords count:3];
-
+
MGLMultiPolygonFeature *multiPolylineFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:@[polygon1, polygon2]];
-
+
// A GeoJSON feature
NSDictionary *geoJSONFeature = [multiPolylineFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"MultiPolygon",
@"coordinates": @[
@@ -284,10 +284,10 @@
CLLocationCoordinate2D coord3 = { 0, 0 };
CLLocationCoordinate2D coords[] = { coord1, coord2, coord3 };
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coords count:3];
-
+
// A GeoJSON feature
NSDictionary *geoJSONFeature = [pointCollectionFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"MultiPoint",
@"coordinates": @[@[@(coord1.longitude), @(coord1.latitude)],
@@ -301,17 +301,17 @@
MGLPointAnnotation *pointFeature = [[MGLPointAnnotation alloc] init];
CLLocationCoordinate2D pointCoordinate = { 10, 10 };
pointFeature.coordinate = pointCoordinate;
-
+
CLLocationCoordinate2D coord1 = { 0, 0 };
CLLocationCoordinate2D coord2 = { 10, 10 };
CLLocationCoordinate2D coords[] = { coord1, coord2 };
MGLPolyline *polyline = [MGLPolyline polylineWithCoordinates:coords count:2];
-
+
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[pointFeature,
polyline]];
// A GeoJSON feature
NSDictionary *geoJSONFeature = [shapeCollectionFeature geoJSONDictionary];
-
+
// it has the correct geometry
NSDictionary *expectedGeometry = @{@"type": @"GeometryCollection",
@"geometries": @[
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm
index fb50512afd..c03b22c399 100644
--- a/platform/darwin/test/MGLFillStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -20,13 +20,13 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
-
+
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
@@ -37,254 +37,343 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::FillLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::FillLayer>();
-
+
// fill-antialias
{
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"fill-antialias should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillAntialiased;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
- layer.fillAntialiased = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
+ layer.fillAntialiased = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { false };
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
@"Setting fillAntialiased to a constant value should update fill-antialias.");
- XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
+ XCTAssertEqualObjects(layer.fillAntialiased, constantStyleValue,
@"fillAntialiased should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillAntialiased = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, false}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillAntialiased = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
- @"Setting fillAntialiased to a function should update fill-antialias.");
- XCTAssertEqualObjects(layer.fillAntialiased, styleValue,
- @"fillAntialiased should round-trip functions.");
-
+ @"Setting fillAntialiased to a camera function should update fill-antialias.");
+ XCTAssertEqualObjects(layer.fillAntialiased, functionStyleValue,
+ @"fillAntialiased should round-trip camera functions.");
+
+
+
layer.fillAntialiased = nil;
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@"Unsetting fillAntialiased should return fill-antialias to the default value.");
XCTAssertEqualObjects(layer.fillAntialiased, defaultStyleValue,
@"fillAntialiased should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillAntialiased = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// fill-color
{
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"fill-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.fillColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.fillColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
@"Setting fillColor to a constant value should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, styleValue,
+ XCTAssertEqualObjects(layer.fillColor, constantStyleValue,
@"fillColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
- @"Setting fillColor to a function should update fill-color.");
- XCTAssertEqualObjects(layer.fillColor, styleValue,
- @"fillColor should round-trip functions.");
-
+ @"Setting fillColor to a camera function should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
+ @"fillColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
+ @"Setting fillColor to a source function should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
+ @"fillColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
+ @"Setting fillColor to a composite function should update fill-color.");
+ XCTAssertEqualObjects(layer.fillColor, functionStyleValue,
+ @"fillColor should round-trip composite functions.");
+
+
layer.fillColor = nil;
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@"Unsetting fillColor should return fill-color to the default value.");
XCTAssertEqualObjects(layer.fillColor, defaultStyleValue,
@"fillColor should return the default value after being unset.");
}
-
+
// fill-opacity
{
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"fill-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.fillOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.fillOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.fillOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
@"Setting fillOpacity to a constant value should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, styleValue,
+ XCTAssertEqualObjects(layer.fillOpacity, constantStyleValue,
@"fillOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
- @"Setting fillOpacity to a function should update fill-opacity.");
- XCTAssertEqualObjects(layer.fillOpacity, styleValue,
- @"fillOpacity should round-trip functions.");
-
+ @"Setting fillOpacity to a camera function should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
+ @"fillOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
+ @"Setting fillOpacity to a source function should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
+ @"fillOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
+ @"Setting fillOpacity to a composite function should update fill-opacity.");
+ XCTAssertEqualObjects(layer.fillOpacity, functionStyleValue,
+ @"fillOpacity should round-trip composite functions.");
+
+
layer.fillOpacity = nil;
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@"Unsetting fillOpacity should return fill-opacity to the default value.");
XCTAssertEqualObjects(layer.fillOpacity, defaultStyleValue,
@"fillOpacity should return the default value after being unset.");
}
-
+
// fill-outline-color
{
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"fill-outline-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.fillOutlineColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.fillOutlineColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.fillOutlineColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
@"Setting fillOutlineColor to a constant value should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
+ XCTAssertEqualObjects(layer.fillOutlineColor, constantStyleValue,
@"fillOutlineColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillOutlineColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillOutlineColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
- @"Setting fillOutlineColor to a function should update fill-outline-color.");
- XCTAssertEqualObjects(layer.fillOutlineColor, styleValue,
- @"fillOutlineColor should round-trip functions.");
-
+ @"Setting fillOutlineColor to a camera function should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
+ @"fillOutlineColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.fillOutlineColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
+ @"Setting fillOutlineColor to a source function should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
+ @"fillOutlineColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.fillOutlineColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
+ @"Setting fillOutlineColor to a composite function should update fill-outline-color.");
+ XCTAssertEqualObjects(layer.fillOutlineColor, functionStyleValue,
+ @"fillOutlineColor should round-trip composite functions.");
+
+
layer.fillOutlineColor = nil;
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@"Unsetting fillOutlineColor should return fill-outline-color to the default value.");
XCTAssertEqualObjects(layer.fillOutlineColor, defaultStyleValue,
@"fillOutlineColor should return the default value after being unset.");
}
-
+
// fill-pattern
{
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"fill-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.fillPattern;
-
- MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"];
- layer.fillPattern = styleValue;
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Fill Pattern"];
+ layer.fillPattern = constantStyleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Fill Pattern" };
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
@"Setting fillPattern to a constant value should update fill-pattern.");
- XCTAssertEqualObjects(layer.fillPattern, styleValue,
+ XCTAssertEqualObjects(layer.fillPattern, constantStyleValue,
@"fillPattern should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillPattern = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Fill Pattern"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
- styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillPattern = styleValue;
- propertyValue = { mbgl::style::Function<std::string> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
- @"Setting fillPattern to a function should update fill-pattern.");
- XCTAssertEqualObjects(layer.fillPattern, styleValue,
- @"fillPattern should round-trip functions.");
-
+ @"Setting fillPattern to a camera function should update fill-pattern.");
+ XCTAssertEqualObjects(layer.fillPattern, functionStyleValue,
+ @"fillPattern should round-trip camera functions.");
+
+
+
layer.fillPattern = nil;
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@"Unsetting fillPattern should return fill-pattern to the default value.");
XCTAssertEqualObjects(layer.fillPattern, defaultStyleValue,
@"fillPattern should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// fill-translate
{
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"fill-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslation;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.fillTranslation = styleValue;
+ layer.fillTranslation = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
@"Setting fillTranslation to a constant value should update fill-translate.");
- XCTAssertEqualObjects(layer.fillTranslation, styleValue,
+ XCTAssertEqualObjects(layer.fillTranslation, constantStyleValue,
@"fillTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillTranslation = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
- @"Setting fillTranslation to a function should update fill-translate.");
- XCTAssertEqualObjects(layer.fillTranslation, styleValue,
- @"fillTranslation should round-trip functions.");
-
+ @"Setting fillTranslation to a camera function should update fill-translate.");
+ XCTAssertEqualObjects(layer.fillTranslation, functionStyleValue,
+ @"fillTranslation should round-trip camera functions.");
+
+
+
layer.fillTranslation = nil;
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@"Unsetting fillTranslation should return fill-translate to the default value.");
XCTAssertEqualObjects(layer.fillTranslation, defaultStyleValue,
@"fillTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// fill-translate-anchor
{
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"fill-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.fillTranslationAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]];
- layer.fillTranslationAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLFillTranslationAnchor:MGLFillTranslationAnchorViewport]];
+ layer.fillTranslationAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
@"Setting fillTranslationAnchor to a constant value should update fill-translate-anchor.");
- XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, constantStyleValue,
@"fillTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.fillTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.fillTranslationAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
- @"Setting fillTranslationAnchor to a function should update fill-translate-anchor.");
- XCTAssertEqualObjects(layer.fillTranslationAnchor, styleValue,
- @"fillTranslationAnchor should round-trip functions.");
-
+ @"Setting fillTranslationAnchor to a camera function should update fill-translate-anchor.");
+ XCTAssertEqualObjects(layer.fillTranslationAnchor, functionStyleValue,
+ @"fillTranslationAnchor should round-trip camera functions.");
+
+
+
layer.fillTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
@"Unsetting fillTranslationAnchor should return fill-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, defaultStyleValue,
@"fillTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.fillTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLGeometryTests.mm b/platform/darwin/test/MGLGeometryTests.mm
index 0ffc27b29e..220a837643 100644
--- a/platform/darwin/test/MGLGeometryTests.mm
+++ b/platform/darwin/test/MGLGeometryTests.mm
@@ -15,23 +15,23 @@
}
- (void)testAngleConversions {
- XCTAssertEqualWithAccuracy(-180, MGLDegreesFromRadians(-M_PI), 5);
+ XCTAssertEqualWithAccuracy(-180, MGLDegreesFromRadians(-M_PI), 1e-5);
XCTAssertEqual(0, MGLDegreesFromRadians(0));
- XCTAssertEqualWithAccuracy(45, MGLDegreesFromRadians(M_PI_4), 5);
- XCTAssertEqualWithAccuracy(90, MGLDegreesFromRadians(M_PI_2), 5);
- XCTAssertEqualWithAccuracy(180, MGLDegreesFromRadians(M_PI), 5);
- XCTAssertEqualWithAccuracy(360, MGLDegreesFromRadians(2 * M_PI), 5);
- XCTAssertEqualWithAccuracy(720, MGLDegreesFromRadians(4 * M_PI), 5);
+ XCTAssertEqualWithAccuracy(45, MGLDegreesFromRadians(M_PI_4), 1e-5);
+ XCTAssertEqualWithAccuracy(90, MGLDegreesFromRadians(M_PI_2), 1e-5);
+ XCTAssertEqualWithAccuracy(180, MGLDegreesFromRadians(M_PI), 1e-5);
+ XCTAssertEqualWithAccuracy(360, MGLDegreesFromRadians(2 * M_PI), 1e-5);
+ XCTAssertEqualWithAccuracy(720, MGLDegreesFromRadians(4 * M_PI), 1e-5);
- XCTAssertEqualWithAccuracy(-360, MGLDegreesFromRadians(MGLRadiansFromDegrees(-360)), 4);
- XCTAssertEqualWithAccuracy(-180, MGLDegreesFromRadians(MGLRadiansFromDegrees(-180)), 5);
- XCTAssertEqualWithAccuracy(-90, MGLDegreesFromRadians(MGLRadiansFromDegrees(-90)), 5);
- XCTAssertEqualWithAccuracy(-45, MGLDegreesFromRadians(MGLRadiansFromDegrees(-45)), 5);
- XCTAssertEqualWithAccuracy(0, MGLDegreesFromRadians(MGLRadiansFromDegrees(0)), 5);
- XCTAssertEqualWithAccuracy(45, MGLDegreesFromRadians(MGLRadiansFromDegrees(45)), 5);
- XCTAssertEqualWithAccuracy(90, MGLDegreesFromRadians(MGLRadiansFromDegrees(90)), 5);
- XCTAssertEqualWithAccuracy(180, MGLDegreesFromRadians(MGLRadiansFromDegrees(180)), 5);
- XCTAssertEqualWithAccuracy(360, MGLDegreesFromRadians(MGLRadiansFromDegrees(360)), 4);
+ XCTAssertEqualWithAccuracy(-360, MGLDegreesFromRadians(MGLRadiansFromDegrees(-360)), 1e-4);
+ XCTAssertEqualWithAccuracy(-180, MGLDegreesFromRadians(MGLRadiansFromDegrees(-180)), 1e-5);
+ XCTAssertEqualWithAccuracy(-90, MGLDegreesFromRadians(MGLRadiansFromDegrees(-90)), 1e-5);
+ XCTAssertEqualWithAccuracy(-45, MGLDegreesFromRadians(MGLRadiansFromDegrees(-45)), 1e-5);
+ XCTAssertEqualWithAccuracy(0, MGLDegreesFromRadians(MGLRadiansFromDegrees(0)), 1e-5);
+ XCTAssertEqualWithAccuracy(45, MGLDegreesFromRadians(MGLRadiansFromDegrees(45)), 1e-5);
+ XCTAssertEqualWithAccuracy(90, MGLDegreesFromRadians(MGLRadiansFromDegrees(90)), 1e-5);
+ XCTAssertEqualWithAccuracy(180, MGLDegreesFromRadians(MGLRadiansFromDegrees(180)), 1e-5);
+ XCTAssertEqualWithAccuracy(360, MGLDegreesFromRadians(MGLRadiansFromDegrees(360)), 1e-4);
}
- (void)testAltitudeConversions {
@@ -39,37 +39,37 @@
CGSize midSize = CGSizeMake(600, 800);
CGSize shortSize = CGSizeMake(600, 400);
- XCTAssertEqualWithAccuracy(1800, MGLAltitudeForZoomLevel(MGLZoomLevelForAltitude(1800, 0, 0, midSize), 0, 0, midSize), 1);
+ XCTAssertEqualWithAccuracy(1800, MGLAltitudeForZoomLevel(MGLZoomLevelForAltitude(1800, 0, 0, midSize), 0, 0, midSize), 1e-8);
XCTAssertLessThan(MGLZoomLevelForAltitude(1800, 0, 0, midSize), MGLZoomLevelForAltitude(1800, 0, 0, tallSize));
XCTAssertGreaterThan(MGLZoomLevelForAltitude(1800, 0, 0, midSize), MGLZoomLevelForAltitude(1800, 0, 0, shortSize));
- XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 0, 0, midSize), 0, 0, midSize), 3);
- XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 0, 0, midSize), 0, 0, midSize), 3);
+ XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 0, 0, midSize), 0, 0, midSize), 1e-8);
+ XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 0, 0, midSize), 0, 0, midSize), 1e-8);
- XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 0, 40, midSize), 0, 40, midSize), 3);
- XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 0, 40, midSize), 0, 40, midSize), 3);
+ XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 0, 40, midSize), 0, 40, midSize), 1e-8);
+ XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 0, 40, midSize), 0, 40, midSize), 1e-8);
- XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 60, 40, midSize), 60, 40, midSize), 3);
- XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 60, 40, midSize), 60, 40, midSize), 3);
+ XCTAssertEqualWithAccuracy(0, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(0, 60, 40, midSize), 60, 40, midSize), 1e-8);
+ XCTAssertEqualWithAccuracy(18, MGLZoomLevelForAltitude(MGLAltitudeForZoomLevel(18, 60, 40, midSize), 60, 40, midSize), 1e-8);
}
- (void)testGeometryBoxing {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
CLLocationCoordinate2D roundTrippedCoordinate = [NSValue valueWithMGLCoordinate:coordinate].MGLCoordinateValue;
-
+
XCTAssertEqual(coordinate.latitude, roundTrippedCoordinate.latitude, @"Latitude should round-trip.");
XCTAssertEqual(coordinate.longitude, roundTrippedCoordinate.longitude, @"Longitude should round-trip.");
-
+
MGLCoordinateSpan span = MGLCoordinateSpanMake(4.383333333333335, -4.299999999999997);
MGLCoordinateSpan roundTrippedSpan = [NSValue valueWithMGLCoordinateSpan:span].MGLCoordinateSpanValue;
-
+
XCTAssertEqual(span.latitudeDelta, roundTrippedSpan.latitudeDelta, @"Latitude delta should round-trip.");
XCTAssertEqual(span.longitudeDelta, roundTrippedSpan.longitudeDelta, @"Longitude delta should round-trip.");
-
+
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(38.9131982, -77.0325453144239),
CLLocationCoordinate2DMake(37.7757368, -122.4135302));
MGLCoordinateBounds roundTrippedBounds = [NSValue valueWithMGLCoordinateBounds:bounds].MGLCoordinateBoundsValue;
-
+
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.sw],
[NSValue valueWithMGLCoordinate:roundTrippedBounds.sw],
@"Southwest should round-trip.");
@@ -79,9 +79,9 @@
}
- (void)testCoordinateInCoordinateBounds {
- CLLocationCoordinate2D ne = CLLocationCoordinate2DMake(41, -111);
- CLLocationCoordinate2D sw = CLLocationCoordinate2DMake(45, -104);
- MGLCoordinateBounds wyoming = MGLCoordinateBoundsMake(ne, sw);
+ CLLocationCoordinate2D ne = CLLocationCoordinate2DMake(45, -104);
+ CLLocationCoordinate2D sw = CLLocationCoordinate2DMake(41, -111);
+ MGLCoordinateBounds wyoming = MGLCoordinateBoundsMake(sw, ne);
CLLocationCoordinate2D centerOfWyoming = CLLocationCoordinate2DMake(43, -107.5);
@@ -109,7 +109,7 @@
XCTAssertEqual(feature.attributes.count, 0);
XCTAssertEqual(feature.coordinate.latitude, 0);
XCTAssertEqual(feature.coordinate.longitude, 0);
-
+
data = [@"{\"type\": \"Feature\", \"feature\": {\"type\": \"Point\", \"coordinates\": [0, 0]}}" dataUsingEncoding:NSUTF8StringEncoding];
error = nil;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
@@ -121,7 +121,7 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
feature.identifier = @504;
feature.coordinate = CLLocationCoordinate2DMake(29.95, -90.066667);
-
+
NSData *data = [feature geoJSONDataUsingEncoding:NSUTF8StringEncoding];
XCTAssertNotNil(data, @"MGLPointFeature should serialize as an UTF-8 string data object.");
NSError *error;
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 24a9d7afea..95c3e434c0 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -20,13 +20,13 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
-
+
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
@@ -37,492 +37,652 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::LineLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::LineLayer>();
-
+
// line-cap
{
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"line-cap should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineCap;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]];
- layer.lineCap = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineCap:MGLLineCapSquare]];
+ layer.lineCap = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::LineCapType> propertyValue = { mbgl::style::LineCapType::Square };
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
@"Setting lineCap to a constant value should update line-cap.");
- XCTAssertEqualObjects(layer.lineCap, styleValue,
+ XCTAssertEqualObjects(layer.lineCap, constantStyleValue,
@"lineCap should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineCap = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::LineCapType> intervalStops = { {{18, mbgl::style::LineCapType::Square}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::LineCapType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineCap = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::LineCapType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
- @"Setting lineCap to a function should update line-cap.");
- XCTAssertEqualObjects(layer.lineCap, styleValue,
- @"lineCap should round-trip functions.");
-
+ @"Setting lineCap to a camera function should update line-cap.");
+ XCTAssertEqualObjects(layer.lineCap, functionStyleValue,
+ @"lineCap should round-trip camera functions.");
+
+
+
layer.lineCap = nil;
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@"Unsetting lineCap should return line-cap to the default value.");
XCTAssertEqualObjects(layer.lineCap, defaultStyleValue,
@"lineCap should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineCap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineCap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-join
{
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"line-join should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineJoin;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
- layer.lineJoin = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineJoin:MGLLineJoinMiter]];
+ layer.lineJoin = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::LineJoinType> propertyValue = { mbgl::style::LineJoinType::Miter };
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a constant value should update line-join.");
- XCTAssertEqualObjects(layer.lineJoin, styleValue,
+ XCTAssertEqualObjects(layer.lineJoin, constantStyleValue,
@"lineJoin should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineJoin = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::LineJoinType> intervalStops = { {{18, mbgl::style::LineJoinType::Miter}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::LineJoinType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineJoin = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::LineJoinType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
- @"Setting lineJoin to a function should update line-join.");
- XCTAssertEqualObjects(layer.lineJoin, styleValue,
- @"lineJoin should round-trip functions.");
-
+ @"Setting lineJoin to a camera function should update line-join.");
+ XCTAssertEqualObjects(layer.lineJoin, functionStyleValue,
+ @"lineJoin should round-trip camera functions.");
+
+
+
layer.lineJoin = nil;
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@"Unsetting lineJoin should return line-join to the default value.");
XCTAssertEqualObjects(layer.lineJoin, defaultStyleValue,
@"lineJoin should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineJoin = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-miter-limit
{
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"line-miter-limit should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineMiterLimit;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineMiterLimit = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineMiterLimit = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
@"Setting lineMiterLimit to a constant value should update line-miter-limit.");
- XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
+ XCTAssertEqualObjects(layer.lineMiterLimit, constantStyleValue,
@"lineMiterLimit should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineMiterLimit = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineMiterLimit = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
- @"Setting lineMiterLimit to a function should update line-miter-limit.");
- XCTAssertEqualObjects(layer.lineMiterLimit, styleValue,
- @"lineMiterLimit should round-trip functions.");
-
+ @"Setting lineMiterLimit to a camera function should update line-miter-limit.");
+ XCTAssertEqualObjects(layer.lineMiterLimit, functionStyleValue,
+ @"lineMiterLimit should round-trip camera functions.");
+
+
+
layer.lineMiterLimit = nil;
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@"Unsetting lineMiterLimit should return line-miter-limit to the default value.");
XCTAssertEqualObjects(layer.lineMiterLimit, defaultStyleValue,
@"lineMiterLimit should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineMiterLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-round-limit
{
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"line-round-limit should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineRoundLimit;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineRoundLimit = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineRoundLimit = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
@"Setting lineRoundLimit to a constant value should update line-round-limit.");
- XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
+ XCTAssertEqualObjects(layer.lineRoundLimit, constantStyleValue,
@"lineRoundLimit should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineRoundLimit = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineRoundLimit = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
- @"Setting lineRoundLimit to a function should update line-round-limit.");
- XCTAssertEqualObjects(layer.lineRoundLimit, styleValue,
- @"lineRoundLimit should round-trip functions.");
-
+ @"Setting lineRoundLimit to a camera function should update line-round-limit.");
+ XCTAssertEqualObjects(layer.lineRoundLimit, functionStyleValue,
+ @"lineRoundLimit should round-trip camera functions.");
+
+
+
layer.lineRoundLimit = nil;
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@"Unsetting lineRoundLimit should return line-round-limit to the default value.");
XCTAssertEqualObjects(layer.lineRoundLimit, defaultStyleValue,
@"lineRoundLimit should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineRoundLimit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-blur
{
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"line-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineBlur;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineBlur = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineBlur = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
@"Setting lineBlur to a constant value should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, styleValue,
+ XCTAssertEqualObjects(layer.lineBlur, constantStyleValue,
@"lineBlur should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineBlur = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineBlur = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
- @"Setting lineBlur to a function should update line-blur.");
- XCTAssertEqualObjects(layer.lineBlur, styleValue,
- @"lineBlur should round-trip functions.");
-
+ @"Setting lineBlur to a camera function should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
+ @"lineBlur should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineBlur = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
+ @"Setting lineBlur to a source function should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
+ @"lineBlur should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineBlur = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
+ @"Setting lineBlur to a composite function should update line-blur.");
+ XCTAssertEqualObjects(layer.lineBlur, functionStyleValue,
+ @"lineBlur should round-trip composite functions.");
+
+
layer.lineBlur = nil;
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@"Unsetting lineBlur should return line-blur to the default value.");
XCTAssertEqualObjects(layer.lineBlur, defaultStyleValue,
@"lineBlur should return the default value after being unset.");
}
-
+
// line-color
{
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"line-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.lineColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.lineColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.lineColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
@"Setting lineColor to a constant value should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, styleValue,
+ XCTAssertEqualObjects(layer.lineColor, constantStyleValue,
@"lineColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
- @"Setting lineColor to a function should update line-color.");
- XCTAssertEqualObjects(layer.lineColor, styleValue,
- @"lineColor should round-trip functions.");
-
+ @"Setting lineColor to a camera function should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
+ @"lineColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
+ @"Setting lineColor to a source function should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
+ @"lineColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
+ @"Setting lineColor to a composite function should update line-color.");
+ XCTAssertEqualObjects(layer.lineColor, functionStyleValue,
+ @"lineColor should round-trip composite functions.");
+
+
layer.lineColor = nil;
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@"Unsetting lineColor should return line-color to the default value.");
XCTAssertEqualObjects(layer.lineColor, defaultStyleValue,
@"lineColor should return the default value after being unset.");
}
-
+
// line-dasharray
{
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"line-dasharray should be unset initially.");
MGLStyleValue<NSArray<NSNumber *> *> *defaultStyleValue = layer.lineDashPattern;
-
- MGLStyleValue<NSArray<NSNumber *> *> *styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
- layer.lineDashPattern = styleValue;
+
+ MGLStyleValue<NSArray<NSNumber *> *> *constantStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithRawValue:@[@1, @2]];
+ layer.lineDashPattern = constantStyleValue;
mbgl::style::PropertyValue<std::vector<float>> propertyValue = { {1, 2} };
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
@"Setting lineDashPattern to a constant value should update line-dasharray.");
- XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
+ XCTAssertEqualObjects(layer.lineDashPattern, constantStyleValue,
@"lineDashPattern should round-trip constant values.");
+
+ MGLStyleValue<NSArray<NSNumber *> *> * functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineDashPattern = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::vector<float>> intervalStops = { {{18, {1, 2}}} };
+ propertyValue = mbgl::style::CameraFunction<std::vector<float>> { intervalStops };
- styleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineDashPattern = styleValue;
- propertyValue = { mbgl::style::Function<std::vector<float>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
- @"Setting lineDashPattern to a function should update line-dasharray.");
- XCTAssertEqualObjects(layer.lineDashPattern, styleValue,
- @"lineDashPattern should round-trip functions.");
-
+ @"Setting lineDashPattern to a camera function should update line-dasharray.");
+ XCTAssertEqualObjects(layer.lineDashPattern, functionStyleValue,
+ @"lineDashPattern should round-trip camera functions.");
+
+
+
layer.lineDashPattern = nil;
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@"Unsetting lineDashPattern should return line-dasharray to the default value.");
XCTAssertEqualObjects(layer.lineDashPattern, defaultStyleValue,
@"lineDashPattern should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSArray<NSNumber *> *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineDashPattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-gap-width
{
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"line-gap-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineGapWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineGapWidth = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineGapWidth = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
@"Setting lineGapWidth to a constant value should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
+ XCTAssertEqualObjects(layer.lineGapWidth, constantStyleValue,
@"lineGapWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineGapWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineGapWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
- @"Setting lineGapWidth to a function should update line-gap-width.");
- XCTAssertEqualObjects(layer.lineGapWidth, styleValue,
- @"lineGapWidth should round-trip functions.");
-
+ @"Setting lineGapWidth to a camera function should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
+ @"lineGapWidth should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineGapWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
+ @"Setting lineGapWidth to a source function should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
+ @"lineGapWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineGapWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
+ @"Setting lineGapWidth to a composite function should update line-gap-width.");
+ XCTAssertEqualObjects(layer.lineGapWidth, functionStyleValue,
+ @"lineGapWidth should round-trip composite functions.");
+
+
layer.lineGapWidth = nil;
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@"Unsetting lineGapWidth should return line-gap-width to the default value.");
XCTAssertEqualObjects(layer.lineGapWidth, defaultStyleValue,
@"lineGapWidth should return the default value after being unset.");
}
-
+
// line-offset
{
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"line-offset should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOffset;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineOffset = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineOffset = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
@"Setting lineOffset to a constant value should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, styleValue,
+ XCTAssertEqualObjects(layer.lineOffset, constantStyleValue,
@"lineOffset should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineOffset = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineOffset = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
- @"Setting lineOffset to a function should update line-offset.");
- XCTAssertEqualObjects(layer.lineOffset, styleValue,
- @"lineOffset should round-trip functions.");
-
+ @"Setting lineOffset to a camera function should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
+ @"lineOffset should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineOffset = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
+ @"Setting lineOffset to a source function should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
+ @"lineOffset should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineOffset = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
+ @"Setting lineOffset to a composite function should update line-offset.");
+ XCTAssertEqualObjects(layer.lineOffset, functionStyleValue,
+ @"lineOffset should round-trip composite functions.");
+
+
layer.lineOffset = nil;
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@"Unsetting lineOffset should return line-offset to the default value.");
XCTAssertEqualObjects(layer.lineOffset, defaultStyleValue,
@"lineOffset should return the default value after being unset.");
}
-
+
// line-opacity
{
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"line-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
@"Setting lineOpacity to a constant value should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, styleValue,
+ XCTAssertEqualObjects(layer.lineOpacity, constantStyleValue,
@"lineOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
- @"Setting lineOpacity to a function should update line-opacity.");
- XCTAssertEqualObjects(layer.lineOpacity, styleValue,
- @"lineOpacity should round-trip functions.");
-
+ @"Setting lineOpacity to a camera function should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
+ @"lineOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
+ @"Setting lineOpacity to a source function should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
+ @"lineOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
+ @"Setting lineOpacity to a composite function should update line-opacity.");
+ XCTAssertEqualObjects(layer.lineOpacity, functionStyleValue,
+ @"lineOpacity should round-trip composite functions.");
+
+
layer.lineOpacity = nil;
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@"Unsetting lineOpacity should return line-opacity to the default value.");
XCTAssertEqualObjects(layer.lineOpacity, defaultStyleValue,
@"lineOpacity should return the default value after being unset.");
}
-
+
// line-pattern
{
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"line-pattern should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.linePattern;
-
- MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"];
- layer.linePattern = styleValue;
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Line Pattern"];
+ layer.linePattern = constantStyleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Line Pattern" };
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
@"Setting linePattern to a constant value should update line-pattern.");
- XCTAssertEqualObjects(layer.linePattern, styleValue,
+ XCTAssertEqualObjects(layer.linePattern, constantStyleValue,
@"linePattern should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.linePattern = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Line Pattern"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
- styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.linePattern = styleValue;
- propertyValue = { mbgl::style::Function<std::string> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
- @"Setting linePattern to a function should update line-pattern.");
- XCTAssertEqualObjects(layer.linePattern, styleValue,
- @"linePattern should round-trip functions.");
-
+ @"Setting linePattern to a camera function should update line-pattern.");
+ XCTAssertEqualObjects(layer.linePattern, functionStyleValue,
+ @"linePattern should round-trip camera functions.");
+
+
+
layer.linePattern = nil;
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@"Unsetting linePattern should return line-pattern to the default value.");
XCTAssertEqualObjects(layer.linePattern, defaultStyleValue,
@"linePattern should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.linePattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.linePattern = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-translate
{
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"line-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslation;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.lineTranslation = styleValue;
+ layer.lineTranslation = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
@"Setting lineTranslation to a constant value should update line-translate.");
- XCTAssertEqualObjects(layer.lineTranslation, styleValue,
+ XCTAssertEqualObjects(layer.lineTranslation, constantStyleValue,
@"lineTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineTranslation = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
- @"Setting lineTranslation to a function should update line-translate.");
- XCTAssertEqualObjects(layer.lineTranslation, styleValue,
- @"lineTranslation should round-trip functions.");
-
+ @"Setting lineTranslation to a camera function should update line-translate.");
+ XCTAssertEqualObjects(layer.lineTranslation, functionStyleValue,
+ @"lineTranslation should round-trip camera functions.");
+
+
+
layer.lineTranslation = nil;
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@"Unsetting lineTranslation should return line-translate to the default value.");
XCTAssertEqualObjects(layer.lineTranslation, defaultStyleValue,
@"lineTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-translate-anchor
{
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"line-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.lineTranslationAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]];
- layer.lineTranslationAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLLineTranslationAnchor:MGLLineTranslationAnchorViewport]];
+ layer.lineTranslationAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
@"Setting lineTranslationAnchor to a constant value should update line-translate-anchor.");
- XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, constantStyleValue,
@"lineTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineTranslationAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
- @"Setting lineTranslationAnchor to a function should update line-translate-anchor.");
- XCTAssertEqualObjects(layer.lineTranslationAnchor, styleValue,
- @"lineTranslationAnchor should round-trip functions.");
-
+ @"Setting lineTranslationAnchor to a camera function should update line-translate-anchor.");
+ XCTAssertEqualObjects(layer.lineTranslationAnchor, functionStyleValue,
+ @"lineTranslationAnchor should round-trip camera functions.");
+
+
+
layer.lineTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@"Unsetting lineTranslationAnchor should return line-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, defaultStyleValue,
@"lineTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// line-width
{
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"line-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.lineWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.lineWidth = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.lineWidth = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a constant value should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, styleValue,
+ XCTAssertEqualObjects(layer.lineWidth, constantStyleValue,
@"lineWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.lineWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.lineWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
- @"Setting lineWidth to a function should update line-width.");
- XCTAssertEqualObjects(layer.lineWidth, styleValue,
- @"lineWidth should round-trip functions.");
-
+ @"Setting lineWidth to a camera function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
+ @"lineWidth should round-trip camera functions.");
+
+
+
layer.lineWidth = nil;
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
@"Unsetting lineWidth should return line-width to the default value.");
XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
@"lineWidth should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m
index 0c8a9f8143..f07f2c1423 100644
--- a/platform/darwin/test/MGLNSStringAdditionsTests.m
+++ b/platform/darwin/test/MGLNSStringAdditionsTests.m
@@ -10,31 +10,31 @@
- (void)testTitleCasedString {
NSLocale *locale = [NSLocale currentLocale];
-
+
XCTAssertEqualObjects([@"© OpenStreetMap" mgl_titleCasedStringWithLocale:locale], @"© OpenStreetMap");
XCTAssertEqualObjects([@"© OSM" mgl_titleCasedStringWithLocale:locale], @"© OSM");
-
+
XCTAssertEqualObjects([@"Improve this map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
XCTAssertEqualObjects([@"Improve This Map" mgl_titleCasedStringWithLocale:locale], @"Improve This Map");
-
+
XCTAssertEqualObjects([@"Improve the map" mgl_titleCasedStringWithLocale:locale], @"Improve the Map");
XCTAssertEqualObjects([@"Improve The Map" mgl_titleCasedStringWithLocale:locale], @"Improve The Map");
-
+
XCTAssertEqualObjects([@"Improve a map" mgl_titleCasedStringWithLocale:locale], @"Improve a Map");
XCTAssertEqualObjects([@"Improve A Map" mgl_titleCasedStringWithLocale:locale], @"Improve A Map");
-
+
XCTAssertEqualObjects([@"Improve for the map" mgl_titleCasedStringWithLocale:locale], @"Improve for the Map");
XCTAssertEqualObjects([@"Improve For The Map" mgl_titleCasedStringWithLocale:locale], @"Improve For The Map");
-
+
XCTAssertEqualObjects([@"Improve and map" mgl_titleCasedStringWithLocale:locale], @"Improve and Map");
XCTAssertEqualObjects([@"Improve And Map" mgl_titleCasedStringWithLocale:locale], @"Improve And Map");
-
+
XCTAssertEqualObjects([@"Improve while mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
XCTAssertEqualObjects([@"Improve While Mapping" mgl_titleCasedStringWithLocale:locale], @"Improve While Mapping");
-
+
XCTAssertEqualObjects([@"Improve with the map" mgl_titleCasedStringWithLocale:locale], @"Improve With the Map");
XCTAssertEqualObjects([@"Improve With The Map" mgl_titleCasedStringWithLocale:locale], @"Improve With The Map");
-
+
XCTAssertEqualObjects([@"Improve this iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
XCTAssertEqualObjects([@"Improve This iPhone" mgl_titleCasedStringWithLocale:locale], @"Improve This iPhone");
}
diff --git a/platform/darwin/test/MGLOfflinePackTests.m b/platform/darwin/test/MGLOfflinePackTests.m
index fa231ba005..f58f306e5d 100644
--- a/platform/darwin/test/MGLOfflinePackTests.m
+++ b/platform/darwin/test/MGLOfflinePackTests.m
@@ -9,9 +9,9 @@
- (void)testInvalidation {
MGLOfflinePack *invalidPack = [[MGLOfflinePack alloc] init];
-
+
XCTAssertEqual(invalidPack.state, MGLOfflinePackStateInvalid, @"Offline pack should be invalid when initialized independently of MGLOfflineStorage.");
-
+
XCTAssertThrowsSpecificNamed(invalidPack.region, NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when accessing its region.");
XCTAssertThrowsSpecificNamed(invalidPack.context, NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when accessing its context.");
XCTAssertThrowsSpecificNamed([invalidPack resume], NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when being resumed.");
@@ -28,7 +28,7 @@
.maximumResourcesExpected = UINT64_MAX,
};
MGLOfflinePackProgress roundTrippedProgress = [NSValue valueWithMGLOfflinePackProgress:progress].MGLOfflinePackProgressValue;
-
+
XCTAssertEqual(progress.countOfResourcesCompleted, roundTrippedProgress.countOfResourcesCompleted, @"Completed resources should round-trip.");
XCTAssertEqual(progress.countOfResourcesExpected, roundTrippedProgress.countOfResourcesExpected, @"Expected resources should round-trip.");
XCTAssertEqual(progress.countOfBytesCompleted, roundTrippedProgress.countOfBytesCompleted, @"Completed bytes should round-trip.");
diff --git a/platform/darwin/test/MGLOfflineRegionTests.m b/platform/darwin/test/MGLOfflineRegionTests.m
index bb467dd35b..ff079fe798 100644
--- a/platform/darwin/test/MGLOfflineRegionTests.m
+++ b/platform/darwin/test/MGLOfflineRegionTests.m
@@ -12,7 +12,7 @@
MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(kCLLocationCoordinate2DInvalid, kCLLocationCoordinate2DInvalid);
MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:nil bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX];
XCTAssertEqualObjects(region.styleURL, [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion], @"Streets isn’t the default style.");
-
+
NSURL *localURL = [NSURL URLWithString:@"beautiful.style"];
XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, @"Invalid style URL", @"No exception raised when initializing region with a local file URL as the style URL.");
}
@@ -22,7 +22,7 @@
MGLTilePyramidOfflineRegion *original = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] bounds:bounds fromZoomLevel:5 toZoomLevel:10];
MGLTilePyramidOfflineRegion *copy = [original copy];
XCTAssertEqualObjects(original, copy, @"Tile pyramid region should be equal to its copy.");
-
+
XCTAssertEqualObjects(original.styleURL, copy.styleURL, @"Style URL has changed.");
XCTAssert(MGLCoordinateBoundsEqualToCoordinateBounds(original.bounds, copy.bounds), @"Bounds have changed.");
XCTAssertEqual(original.minimumZoomLevel, original.minimumZoomLevel, @"Minimum zoom level has changed.");
diff --git a/platform/darwin/test/MGLOfflineStorageTests.m b/platform/darwin/test/MGLOfflineStorageTests.mm
index 07540b5645..28c6633028 100644
--- a/platform/darwin/test/MGLOfflineStorageTests.m
+++ b/platform/darwin/test/MGLOfflineStorageTests.mm
@@ -1,8 +1,12 @@
#import <Mapbox/Mapbox.h>
+#import "MGLOfflineStorage_Private.h"
+
#import <XCTest/XCTest.h>
-@interface MGLOfflineStorageTests : XCTestCase
+#include <mbgl/util/run_loop.hpp>
+
+@interface MGLOfflineStorageTests : XCTestCase <MGLOfflineStorageDelegate>
@end
@@ -10,12 +14,12 @@
- (void)setUp {
[super setUp];
-
+
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
XCTestExpectation *expectation = [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
- NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
- return changeKind = NSKeyValueChangeSetting;
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ return changeKind == NSKeyValueChangeSetting;
}];
if ([MGLOfflineStorage sharedOfflineStorage].packs) {
[expectation fulfill];
@@ -23,7 +27,7 @@
} else {
[self waitForExpectationsWithTimeout:2 handler:nil];
}
-
+
XCTAssertNotNil([MGLOfflineStorage sharedOfflineStorage].packs, @"Shared offline storage object should have a non-nil collection of packs by this point.");
});
}
@@ -34,7 +38,7 @@
- (void)testAddPack {
NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
-
+
NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8];
/// Somewhere near Grape Grove, Ohio, United States.
MGLCoordinateBounds bounds = {
@@ -43,17 +47,17 @@
};
double zoomLevel = 20;
MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:styleURL bounds:bounds fromZoomLevel:zoomLevel toZoomLevel:zoomLevel];
-
+
NSString *nameKey = @"Name";
NSString *name = @"🍇 Grape Grove";
-
+
NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{
nameKey: name,
}];
-
+
__block MGLOfflinePack *pack;
[self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
- NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
return changeKind == NSKeyValueChangeInsertion && indices.count == 1;
}];
@@ -65,40 +69,40 @@
[additionCompletionHandlerExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:2 handler:nil];
-
+
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks + 1, @"Added pack should have been added to the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks.");
-
+
XCTAssertEqual(pack, [MGLOfflineStorage sharedOfflineStorage].packs.lastObject, @"Pack should be appended to end of packs array.");
-
+
XCTAssertEqualObjects(pack.region, region, @"Added pack’s region has changed.");
-
+
NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:pack.context];
XCTAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline pack isn’t a dictionary.");
XCTAssert([userInfo[nameKey] isKindOfClass:[NSString class]], @"Name of offline pack isn’t a string.");
XCTAssertEqualObjects(userInfo[nameKey], name, @"Name of offline pack has changed.");
-
+
XCTAssertEqual(pack.state, MGLOfflinePackStateInactive, @"New pack should initially have inactive state.");
-
+
[self keyValueObservingExpectationForObject:pack keyPath:@"state" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
- NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
- MGLOfflinePackState state = [change[NSKeyValueChangeNewKey] integerValue];
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
+ const auto state = static_cast<MGLOfflinePackState>([change[NSKeyValueChangeNewKey] longValue]);
return changeKind == NSKeyValueChangeSetting && state == MGLOfflinePackStateInactive;
}];
[self expectationForNotification:MGLOfflinePackProgressChangedNotification object:pack handler:^BOOL(NSNotification * _Nonnull notification) {
MGLOfflinePack *notificationPack = notification.object;
XCTAssert([notificationPack isKindOfClass:[MGLOfflinePack class]], @"Object of notification should be an MGLOfflinePack.");
-
+
NSDictionary *userInfo = notification.userInfo;
XCTAssertNotNil(userInfo, @"Progress change notification should have a userInfo dictionary.");
-
+
NSNumber *stateNumber = userInfo[MGLOfflinePackUserInfoKeyState];
XCTAssert([stateNumber isKindOfClass:[NSNumber class]], @"Progress change notification’s state should be an NSNumber.");
XCTAssertEqual(stateNumber.integerValue, pack.state, @"State in a progress change notification should match the pack’s state.");
-
+
NSValue *progressValue = userInfo[MGLOfflinePackUserInfoKeyProgress];
XCTAssert([progressValue isKindOfClass:[NSValue class]], @"Progress change notification’s progress should be an NSValue.");
XCTAssertEqualObjects(progressValue, [NSValue valueWithMGLOfflinePackProgress:pack.progress], @"Progress change notification’s progress should match pack’s progress.");
-
+
return notificationPack == pack && pack.state == MGLOfflinePackStateInactive;
}];
[pack requestProgress];
@@ -131,14 +135,14 @@
- (void)testRemovePack {
NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count;
-
+
MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs.lastObject;
XCTAssertNotNil(pack, @"Added pack should still exist.");
-
+
[self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) {
- NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
+ const auto changeKind = static_cast<NSKeyValueChange>([change[NSKeyValueChangeKindKey] unsignedLongValue]);
NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
- return changeKind = NSKeyValueChangeRemoval && indices.count == 1;
+ return changeKind == NSKeyValueChangeRemoval && indices.count == 1;
}];
XCTestExpectation *completionHandlerExpectation = [self expectationWithDescription:@"remove pack completion handler"];
[[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:^(NSError * _Nullable error) {
@@ -146,9 +150,9 @@
[completionHandlerExpectation fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
-
+
XCTAssertEqual(pack.state, MGLOfflinePackStateInvalid, @"Removed pack should have been invalidated synchronously.");
-
+
XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks - 1, @"Removed pack should have been removed from the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks or -testAddPack.");
}
@@ -156,4 +160,36 @@
XCTAssertGreaterThan([MGLOfflineStorage sharedOfflineStorage].countOfBytesCompleted, 0);
}
+- (NSURL *)offlineStorage:(MGLOfflineStorage *)storage
+ URLForResourceOfKind:(MGLResourceKind)kind
+ withURL:(NSURL *)url {
+ if ([url.scheme isEqual: @"test"] && [url.host isEqual: @"api"]) {
+ return [NSURL URLWithString:@"https://api.mapbox.com"];
+ } else {
+ return url;
+ }
+}
+
+- (void)testResourceTransform {
+ MGLOfflineStorage *os = [MGLOfflineStorage sharedOfflineStorage];
+ [os setDelegate:self];
+
+ auto fs = os.mbglFileSource;
+
+ // Delegate returns "https://api.mapbox.com" as a replacement URL.
+ const mbgl::Resource resource { mbgl::Resource::Unknown, "test://api" };
+ std::unique_ptr<mbgl::AsyncRequest> req;
+ req = fs->request(resource, [&](mbgl::Response res) {
+ req.reset();
+ XCTAssertFalse(res.error.get(), @"Request should not return an error");
+ XCTAssertTrue(res.data.get(), @"Request should return data");
+ XCTAssertEqual("{\"api\":\"mapbox\"}", *res.data, @"Request did not return expected data");
+ CFRunLoopStop(CFRunLoopGetCurrent());
+ });
+
+ CFRunLoopRun();
+
+ [os setDelegate:nil];
+}
+
@end
diff --git a/platform/darwin/test/MGLPredicateTests.mm b/platform/darwin/test/MGLPredicateTests.mm
index fbd144d28a..6e6951dcdd 100644
--- a/platform/darwin/test/MGLPredicateTests.mm
+++ b/platform/darwin/test/MGLPredicateTests.mm
@@ -29,13 +29,13 @@ namespace mbgl {
mbgl::style::AllFilter expected;
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithValue:NO].mgl_filter;
mbgl::style::AnyFilter expected;
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a = 'b'"].mgl_filter;
mbgl::style::EqualsFilter expected = { .key = "a", .value = std::string("b") };
@@ -43,47 +43,83 @@ namespace mbgl {
}
{
+ auto actual = [NSPredicate predicateWithFormat:@"%K = 'Point'", @"$type"].mgl_filter;
+ mbgl::style::TypeEqualsFilter expected = { .value = mbgl::FeatureType::Point };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K = 67086180", @"$id"].mgl_filter;
+ mbgl::style::IdentifierEqualsFilter expected = { .value = UINT64_C(67086180) };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K = nil", @"$id"].mgl_filter;
+ mbgl::style::NotHasIdentifierFilter expected;
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
auto actual = [NSPredicate predicateWithFormat:@"a = nil"].mgl_filter;
mbgl::style::NotHasFilter expected = { .key = "a" };
MGLAssertEqualFilters(actual, expected);
}
{
+ auto actual = [NSPredicate predicateWithFormat:@"%K != 'Point'", @"$type"].mgl_filter;
+ mbgl::style::TypeNotEqualsFilter expected = { .value = mbgl::FeatureType::Point };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K != 67086180", @"$id"].mgl_filter;
+ mbgl::style::IdentifierNotEqualsFilter expected = { .value = UINT64_C(67086180) };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"].mgl_filter;
+ mbgl::style::HasIdentifierFilter expected;
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
auto actual = [NSPredicate predicateWithFormat:@"a != 'b'"].mgl_filter;
mbgl::style::NotEqualsFilter expected = { .key = "a", .value = std::string("b") };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a != nil"].mgl_filter;
mbgl::style::HasFilter expected = { .key = "a" };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a < 'b'"].mgl_filter;
mbgl::style::LessThanFilter expected = { .key = "a", .value = std::string("b") };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a <= 'b'"].mgl_filter;
mbgl::style::LessThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a > 'b'"].mgl_filter;
mbgl::style::GreaterThanFilter expected = { .key = "a", .value = std::string("b") };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a >= 'b'"].mgl_filter;
mbgl::style::GreaterThanEqualsFilter expected = { .key = "a", .value = std::string("b") };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"].mgl_filter;
mbgl::style::AllFilter expected = {
@@ -94,7 +130,7 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@"b", @"z"]].mgl_filter;
mbgl::style::AllFilter expected = {
@@ -105,36 +141,78 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].mgl_filter;
mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a IN %@", @[@"b", @"c"]].mgl_filter;
mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException);
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K IN {'LineString', 'Polygon'}", @"$type"].mgl_filter;
+ mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$type", @[@"LineString", @"Polygon"]].mgl_filter;
+ mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"].mgl_filter;
+ mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ MGLAssertEqualFilters(actual, expected);
+ }
{
+ auto actual = [NSPredicate predicateWithFormat:@"%K IN %@", @"$id", @[@67086180, @3709678893, @3352016856, @4189833989]].mgl_filter;
+ mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"'Mapbox' IN a"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ {
auto actual = [NSPredicate predicateWithFormat:@"{'b', 'c'} CONTAINS a"].mgl_filter;
mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
mbgl::style::InFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
- XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException);
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@"LineString", @"Polygon"], @"$type"].mgl_filter;
+ mbgl::style::TypeInFilter expected = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ {
+ auto actual = [NSPredicate predicateWithFormat:@"{67086180, 3709678893, 3352016856, 4189833989} CONTAINS %K", @"$id"].mgl_filter;
+ mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ MGLAssertEqualFilters(actual, expected);
+ }
{
+ auto actual = [NSPredicate predicateWithFormat:@"%@ CONTAINS %K", @[@67086180, @3709678893, @3352016856, @4189833989], @"$id"].mgl_filter;
+ mbgl::style::IdentifierInFilter expected = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ MGLAssertEqualFilters(actual, expected);
+ }
+
+ XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a CONTAINS 'Mapbox'"].mgl_filter, NSException, NSInvalidArgumentException);
+
+ {
auto actual = [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"].mgl_filter;
mbgl::style::AllFilter expected = {
.filters = {
@@ -144,7 +222,7 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"].mgl_filter;
mbgl::style::AnyFilter expected = {
@@ -155,7 +233,7 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' AND c == 'd')"].mgl_filter;
mbgl::style::NoneFilter expected = {
@@ -170,7 +248,7 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT(a == 'b' OR c == 'd')"].mgl_filter;
mbgl::style::NoneFilter expected = {
@@ -181,50 +259,50 @@ namespace mbgl {
};
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT a == nil"].mgl_filter;
mbgl::style::HasFilter expected = { .key = "a" };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT a != nil"].mgl_filter;
mbgl::style::NotHasFilter expected = { .key = "a" };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].mgl_filter;
mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT a IN %@", @[@"b", @"c"]].mgl_filter;
mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT {'b', 'c'} CONTAINS a"].mgl_filter;
mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
{
auto actual = [NSPredicate predicateWithFormat:@"NOT %@ CONTAINS a", @[@"b", @"c"]].mgl_filter;
mbgl::style::NotInFilter expected = { .key = "a", .values = { std::string("b"), std::string("c") } };
MGLAssertEqualFilters(actual, expected);
}
-
+
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BEGINSWITH 'L'"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a ENDSWITH 'itude'"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a LIKE 'glob?trotter'"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a MATCHES 'i\\w{18}n'"].mgl_filter, NSException, NSInvalidArgumentException);
NSPredicate *selectorPredicate = [NSPredicate predicateWithFormat:@"(SELF isKindOfClass: %@)", [MGLPolyline class]];
XCTAssertThrowsSpecificNamed(selectorPredicate.mgl_filter, NSException, NSInvalidArgumentException);
-
+
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings) {
XCTAssertTrue(NO, @"Predicate block should not be evaluated.");
return NO;
@@ -233,47 +311,100 @@ namespace mbgl {
- (void)testPredication {
XCTAssertNil([NSPredicate mgl_predicateWithFilter:mbgl::style::NullFilter()]);
-
+
{
mbgl::style::EqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = 'b'"]);
}
{
+ mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Point };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'Point'", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::LineString };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'LineString'", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Polygon };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 'Polygon'", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::IdentifierEqualsFilter filter = { .value = UINT64_C(67086180) };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = 67086180", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::NotHasIdentifierFilter filter;
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K = nil", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::TypeEqualsFilter filter = { .value = mbgl::FeatureType::Unknown };
+ XCTAssertThrowsSpecificNamed([NSPredicate mgl_predicateWithFilter:filter], NSException, NSInternalInconsistencyException);
+ }
+
+ {
mbgl::style::NotHasFilter filter = { .key = "a" };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a = nil"]);
}
-
+
{
mbgl::style::NotEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != 'b'"]);
}
{
+ mbgl::style::TypeNotEqualsFilter filter = { .value = mbgl::FeatureType::Point };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != 'Point'", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::IdentifierNotEqualsFilter filter = { .value = UINT64_C(67086180) };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != 67086180", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
+ mbgl::style::HasIdentifierFilter filter;
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K != nil", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
mbgl::style::HasFilter filter = { .key = "a" };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a != nil"]);
}
-
+
{
mbgl::style::LessThanFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a < 'b'"]);
}
-
+
{
mbgl::style::LessThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a <= 'b'"]);
}
-
+
{
mbgl::style::GreaterThanFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a > 'b'"]);
}
-
+
{
mbgl::style::GreaterThanEqualsFilter filter = { .key = "a", .value = std::string("b") };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a >= 'b'"]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -283,7 +414,7 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -293,22 +424,46 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a BETWEEN {'b', 'z'}"]);
}
-
+
{
mbgl::style::InFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"a IN {'b', 'c'}"].predicateFormat);
}
{
+ mbgl::style::TypeInFilter filter = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K IN {'LineString', 'Polygon'}", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, expected.predicateFormat);
+ }
+
+ {
+ mbgl::style::IdentifierInFilter filter = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"%K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
mbgl::style::NotInFilter filter = { .key = "a", .values = { std::string("b"), std::string("c") } };
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, [NSPredicate predicateWithFormat:@"NOT a IN {'b', 'c'}"].predicateFormat);
}
{
+ mbgl::style::TypeNotInFilter filter = { .values = { mbgl::FeatureType::LineString, mbgl::FeatureType::Polygon } };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"NOT %K IN {'LineString', 'Polygon'}", @"$type"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter].predicateFormat, expected.predicateFormat);
+ }
+
+ {
+ mbgl::style::IdentifierNotInFilter filter = { .values = { UINT64_C(67086180), UINT64_C(3709678893), UINT64_C(3352016856), UINT64_C(4189833989) } };
+ NSPredicate *expected = [NSPredicate predicateWithFormat:@"NOT %K IN {67086180, 3709678893, 3352016856, 4189833989}", @"$id"];
+ XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], expected);
+ }
+
+ {
mbgl::style::AllFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
}
-
+
{
mbgl::style::AllFilter filter = {
.filters = {
@@ -318,12 +473,12 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' AND c == 'd'"]);
}
-
+
{
mbgl::style::AnyFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:NO]);
}
-
+
{
mbgl::style::AnyFilter filter = {
.filters = {
@@ -333,12 +488,12 @@ namespace mbgl {
};
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithFormat:@"a == 'b' OR c == 'd'"]);
}
-
+
{
mbgl::style::NoneFilter filter;
XCTAssertEqualObjects([NSPredicate mgl_predicateWithFilter:filter], [NSPredicate predicateWithValue:YES]);
}
-
+
{
mbgl::style::NoneFilter filter = {
.filters = {
@@ -355,20 +510,20 @@ namespace mbgl {
[self testSymmetryWithFormat:@"a != 1" reverseFormat:@"1 != a" mustRoundTrip:YES];
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = b"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"1 = 1"].mgl_filter, NSException, NSInvalidArgumentException);
-
+
// In the predicate format language, $ is a special character denoting a
// variable. Use %K to escape the special feature attribute $id.
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"$id == 670861802"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a = $id"].mgl_filter, NSException, NSInvalidArgumentException);
-
+
[self testSymmetryWithFormat:@"a = nil" reverseFormat:@"nil = a" mustRoundTrip:YES];
[self testSymmetryWithFormat:@"a != nil" reverseFormat:@"nil != a" mustRoundTrip:YES];
-
+
[self testSymmetryWithFormat:@"a < 1" reverseFormat:@"1 > a" mustRoundTrip:YES];
[self testSymmetryWithFormat:@"a <= 1" reverseFormat:@"1 >= a" mustRoundTrip:YES];
[self testSymmetryWithFormat:@"a > 1" reverseFormat:@"1 < a" mustRoundTrip:YES];
[self testSymmetryWithFormat:@"a >= 1" reverseFormat:@"1 <= a" mustRoundTrip:YES];
-
+
[self testSymmetryWithFormat:@"a BETWEEN {1, 2}" reverseFormat:@"1 <= a && 2 >= a" mustRoundTrip:YES];
[self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a BETWEEN %@", @[@1, @2]]
reversePredicate:[NSPredicate predicateWithFormat:@"1 <= a && 2 >= a"]
@@ -378,12 +533,12 @@ namespace mbgl {
XCTAssertThrowsSpecificNamed(betweenSetPredicate.mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1}"].mgl_filter, NSException, NSInvalidArgumentException);
XCTAssertThrowsSpecificNamed([NSPredicate predicateWithFormat:@"a BETWEEN {1, 2, 3}"].mgl_filter, NSException, NSInvalidArgumentException);
-
+
[self testSymmetryWithFormat:@"a IN {1, 2}" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
[self testSymmetryWithPredicate:[NSPredicate predicateWithFormat:@"a IN %@", @[@1, @2]]
reversePredicate:[NSPredicate predicateWithFormat:@"%@ CONTAINS a", @[@1, @2]]
mustRoundTrip:YES];
-
+
// The reverse formats here are a bit backwards because we canonicalize
// a reverse CONTAINS to a forward IN.
[self testSymmetryWithFormat:@"{1, 2} CONTAINS a" reverseFormat:@"{1, 2} CONTAINS a" mustRoundTrip:NO];
@@ -406,12 +561,12 @@ namespace mbgl {
// example, so compare formats instead of the predicates themselves.
XCTAssertEqualObjects(forwardPredicate.predicateFormat, forwardPredicateAfter.predicateFormat);
}
-
+
if (reversePredicate) {
auto reverseFilter = reversePredicate.mgl_filter;
NSPredicate *reversePredicateAfter = [NSPredicate mgl_predicateWithFilter:reverseFilter];
XCTAssertNotEqualObjects(reversePredicate, reversePredicateAfter);
-
+
XCTAssertEqualObjects(forwardPredicateAfter, reversePredicateAfter);
}
}
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm
index 28a201961c..b7a764e6c2 100644
--- a/platform/darwin/test/MGLRasterStyleLayerTests.mm
+++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -19,248 +19,283 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLRasterStyleLayer *layer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::RasterLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::RasterLayer>();
-
+
// raster-brightness-max
{
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@"raster-brightness-max should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumRasterBrightness;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumRasterBrightness = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumRasterBrightness = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
@"Setting maximumRasterBrightness to a constant value should update raster-brightness-max.");
- XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue,
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, constantStyleValue,
@"maximumRasterBrightness should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.maximumRasterBrightness = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.maximumRasterBrightness = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
- @"Setting maximumRasterBrightness to a function should update raster-brightness-max.");
- XCTAssertEqualObjects(layer.maximumRasterBrightness, styleValue,
- @"maximumRasterBrightness should round-trip functions.");
-
+ @"Setting maximumRasterBrightness to a camera function should update raster-brightness-max.");
+ XCTAssertEqualObjects(layer.maximumRasterBrightness, functionStyleValue,
+ @"maximumRasterBrightness should round-trip camera functions.");
+
+
+
layer.maximumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@"Unsetting maximumRasterBrightness should return raster-brightness-max to the default value.");
XCTAssertEqualObjects(layer.maximumRasterBrightness, defaultStyleValue,
@"maximumRasterBrightness should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-brightness-min
{
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@"raster-brightness-min should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.minimumRasterBrightness;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.minimumRasterBrightness = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.minimumRasterBrightness = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
@"Setting minimumRasterBrightness to a constant value should update raster-brightness-min.");
- XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue,
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, constantStyleValue,
@"minimumRasterBrightness should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.minimumRasterBrightness = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.minimumRasterBrightness = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
- @"Setting minimumRasterBrightness to a function should update raster-brightness-min.");
- XCTAssertEqualObjects(layer.minimumRasterBrightness, styleValue,
- @"minimumRasterBrightness should round-trip functions.");
-
+ @"Setting minimumRasterBrightness to a camera function should update raster-brightness-min.");
+ XCTAssertEqualObjects(layer.minimumRasterBrightness, functionStyleValue,
+ @"minimumRasterBrightness should round-trip camera functions.");
+
+
+
layer.minimumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@"Unsetting minimumRasterBrightness should return raster-brightness-min to the default value.");
XCTAssertEqualObjects(layer.minimumRasterBrightness, defaultStyleValue,
@"minimumRasterBrightness should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.minimumRasterBrightness = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-contrast
{
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@"raster-contrast should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterContrast;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterContrast = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterContrast = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
@"Setting rasterContrast to a constant value should update raster-contrast.");
- XCTAssertEqualObjects(layer.rasterContrast, styleValue,
+ XCTAssertEqualObjects(layer.rasterContrast, constantStyleValue,
@"rasterContrast should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.rasterContrast = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.rasterContrast = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
- @"Setting rasterContrast to a function should update raster-contrast.");
- XCTAssertEqualObjects(layer.rasterContrast, styleValue,
- @"rasterContrast should round-trip functions.");
-
+ @"Setting rasterContrast to a camera function should update raster-contrast.");
+ XCTAssertEqualObjects(layer.rasterContrast, functionStyleValue,
+ @"rasterContrast should round-trip camera functions.");
+
+
+
layer.rasterContrast = nil;
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@"Unsetting rasterContrast should return raster-contrast to the default value.");
XCTAssertEqualObjects(layer.rasterContrast, defaultStyleValue,
@"rasterContrast should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterContrast = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-fade-duration
{
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@"raster-fade-duration should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterFadeDuration;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterFadeDuration = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterFadeDuration = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
@"Setting rasterFadeDuration to a constant value should update raster-fade-duration.");
- XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue,
+ XCTAssertEqualObjects(layer.rasterFadeDuration, constantStyleValue,
@"rasterFadeDuration should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.rasterFadeDuration = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.rasterFadeDuration = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
- @"Setting rasterFadeDuration to a function should update raster-fade-duration.");
- XCTAssertEqualObjects(layer.rasterFadeDuration, styleValue,
- @"rasterFadeDuration should round-trip functions.");
-
+ @"Setting rasterFadeDuration to a camera function should update raster-fade-duration.");
+ XCTAssertEqualObjects(layer.rasterFadeDuration, functionStyleValue,
+ @"rasterFadeDuration should round-trip camera functions.");
+
+
+
layer.rasterFadeDuration = nil;
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@"Unsetting rasterFadeDuration should return raster-fade-duration to the default value.");
XCTAssertEqualObjects(layer.rasterFadeDuration, defaultStyleValue,
@"rasterFadeDuration should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterFadeDuration = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-hue-rotate
{
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@"raster-hue-rotate should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterHueRotation;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterHueRotation = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterHueRotation = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
@"Setting rasterHueRotation to a constant value should update raster-hue-rotate.");
- XCTAssertEqualObjects(layer.rasterHueRotation, styleValue,
+ XCTAssertEqualObjects(layer.rasterHueRotation, constantStyleValue,
@"rasterHueRotation should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.rasterHueRotation = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.rasterHueRotation = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
- @"Setting rasterHueRotation to a function should update raster-hue-rotate.");
- XCTAssertEqualObjects(layer.rasterHueRotation, styleValue,
- @"rasterHueRotation should round-trip functions.");
-
+ @"Setting rasterHueRotation to a camera function should update raster-hue-rotate.");
+ XCTAssertEqualObjects(layer.rasterHueRotation, functionStyleValue,
+ @"rasterHueRotation should round-trip camera functions.");
+
+
+
layer.rasterHueRotation = nil;
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@"Unsetting rasterHueRotation should return raster-hue-rotate to the default value.");
XCTAssertEqualObjects(layer.rasterHueRotation, defaultStyleValue,
@"rasterHueRotation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterHueRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-opacity
{
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@"raster-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterOpacity = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterOpacity = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
@"Setting rasterOpacity to a constant value should update raster-opacity.");
- XCTAssertEqualObjects(layer.rasterOpacity, styleValue,
+ XCTAssertEqualObjects(layer.rasterOpacity, constantStyleValue,
@"rasterOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.rasterOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.rasterOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
- @"Setting rasterOpacity to a function should update raster-opacity.");
- XCTAssertEqualObjects(layer.rasterOpacity, styleValue,
- @"rasterOpacity should round-trip functions.");
-
+ @"Setting rasterOpacity to a camera function should update raster-opacity.");
+ XCTAssertEqualObjects(layer.rasterOpacity, functionStyleValue,
+ @"rasterOpacity should round-trip camera functions.");
+
+
+
layer.rasterOpacity = nil;
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@"Unsetting rasterOpacity should return raster-opacity to the default value.");
XCTAssertEqualObjects(layer.rasterOpacity, defaultStyleValue,
@"rasterOpacity should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterOpacity = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// raster-saturation
{
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
@"raster-saturation should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.rasterSaturation;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.rasterSaturation = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.rasterSaturation = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
@"Setting rasterSaturation to a constant value should update raster-saturation.");
- XCTAssertEqualObjects(layer.rasterSaturation, styleValue,
+ XCTAssertEqualObjects(layer.rasterSaturation, constantStyleValue,
@"rasterSaturation should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.rasterSaturation = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.rasterSaturation = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
- @"Setting rasterSaturation to a function should update raster-saturation.");
- XCTAssertEqualObjects(layer.rasterSaturation, styleValue,
- @"rasterSaturation should round-trip functions.");
-
+ @"Setting rasterSaturation to a camera function should update raster-saturation.");
+ XCTAssertEqualObjects(layer.rasterSaturation, functionStyleValue,
+ @"rasterSaturation should round-trip camera functions.");
+
+
+
layer.rasterSaturation = nil;
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
@"Unsetting rasterSaturation should return raster-saturation to the default value.");
XCTAssertEqualObjects(layer.rasterSaturation, defaultStyleValue,
@"rasterSaturation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.rasterSaturation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm
index cf32b5c821..ba85d76020 100644
--- a/platform/darwin/test/MGLShapeSourceTests.mm
+++ b/platform/darwin/test/MGLShapeSourceTests.mm
@@ -19,7 +19,7 @@
MGLShapeSourceOptionMaximumZoomLevel: @99,
MGLShapeSourceOptionBuffer: @1976,
MGLShapeSourceOptionSimplificationTolerance: @0.42};
-
+
auto mbglOptions = MGLGeoJSONOptionsFromDictionary(options);
XCTAssertTrue(mbglOptions.cluster);
XCTAssertEqual(mbglOptions.clusterRadius, 42);
@@ -27,7 +27,7 @@
XCTAssertEqual(mbglOptions.maxzoom, 99);
XCTAssertEqual(mbglOptions.buffer, 1976);
XCTAssertEqual(mbglOptions.tolerance, 0.42);
-
+
options = @{MGLShapeSourceOptionClustered: @"number 1"};
XCTAssertThrows(MGLGeoJSONOptionsFromDictionary(options));
}
@@ -41,26 +41,26 @@
NSDictionary *options = @{
MGLShapeSourceOptionClustered: @YES,
};
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:[[MGLPointFeature alloc] init] options:options];
XCTAssertTrue([source.shape isKindOfClass:[MGLPointFeature class]]);
-
+
MGLShapeCollectionFeature *feature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[]];
source = [[MGLShapeSource alloc] initWithIdentifier:@"id" shape:feature options:options];
XCTAssertTrue([source.shape isKindOfClass:[MGLShapeCollectionFeature class]]);
}
- (void)testMGLShapeSourceWithDataMultipleFeatures {
-
+
NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}";
-
+
NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:&error];
XCTAssertNil(error);
XCTAssertNotNil(shape);
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:shape options:nil];
-
+
MGLShapeCollection *collection = (MGLShapeCollection *)source.shape;
XCTAssertNotNil(collection);
XCTAssertEqual(collection.shapes.count, 1);
@@ -95,9 +95,9 @@
- (void)testMGLShapeSourceWithPolylineFeatures {
CLLocationCoordinate2D coordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates count:2];
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polylineFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPolylineFeature class]]);
}
@@ -109,7 +109,7 @@
CLLocationCoordinate2DMake(101.0, 1.0),
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
-
+
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5];
polygonFeature.identifier = @"feature-id";
NSString *stringAttribute = @"string";
@@ -123,7 +123,7 @@
@"key-4": arrayValue};
NSArray *arrayOfArrays = @[@[@1, @"string-value", @[@"jagged"]]];
NSArray *arrayOfDictionaries = @[@{@"key": @"value"}];
-
+
polygonFeature.attributes = @{@"name": stringAttribute,
@"bool": boolAttribute,
@"double": doubleAttribute,
@@ -131,9 +131,9 @@
@"array-attribute": arrayValue,
@"array-of-array-attribute": arrayOfArrays,
@"array-of-dictionary-attribute": arrayOfDictionaries};
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polygonFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
MGLPolygonFeature *expectedPolygonFeature = (MGLPolygonFeature *)source.shape;
XCTAssertEqualObjects(expectedPolygonFeature.identifier, polygonFeature.identifier);
@@ -155,20 +155,20 @@
CLLocationCoordinate2DMake(101.0, 1.0),
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
-
+
CLLocationCoordinate2D interiorCoordinates[] = {
CLLocationCoordinate2DMake(100.2, 0.2),
CLLocationCoordinate2DMake(100.8, 0.2),
CLLocationCoordinate2DMake(100.8, 0.8),
CLLocationCoordinate2DMake(100.2, 0.8),
CLLocationCoordinate2DMake(100.2, 0.2)};
-
+
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
-
+
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]];
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:polygonFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPolygonFeature class]]);
}
@@ -179,9 +179,9 @@
CLLocationCoordinate2D secondCoordinates[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *secondPolylineFeature = [MGLPolylineFeature polylineWithCoordinates:secondCoordinates count:2];
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[firstPolylineFeature, secondPolylineFeature]];
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:multiPolylineFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLMultiPolylineFeature class]]);
}
@@ -193,23 +193,23 @@
CLLocationCoordinate2DMake(101.0, 1.0),
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
-
+
CLLocationCoordinate2D interiorCoordinates[] = {
CLLocationCoordinate2DMake(100.2, 0.2),
CLLocationCoordinate2DMake(100.8, 0.2),
CLLocationCoordinate2DMake(100.8, 0.8),
CLLocationCoordinate2DMake(100.2, 0.8),
CLLocationCoordinate2DMake(100.2, 0.2)};
-
+
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
-
+
MGLPolygonFeature *firstPolygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]];
MGLPolygonFeature *secondPolygon = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]];
-
+
MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:@[firstPolygon, secondPolygon]];
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:multiPolygonFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLMultiPolygonFeature class]]);
}
@@ -217,9 +217,9 @@
- (void)testMGLShapeSourceWithPointFeature {
MGLPointFeature *pointFeature = [MGLPointFeature new];
pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2);
-
+
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"souce-id" shape:pointFeature options:nil];
-
+
XCTAssertNotNil(source.shape);
XCTAssertTrue([source.shape isMemberOfClass:[MGLPointFeature class]]);
}
@@ -245,34 +245,34 @@
CLLocationCoordinate2DMake(101.0, 1.0),
CLLocationCoordinate2DMake(100.0, 1.0),
CLLocationCoordinate2DMake(100.0, 0.0)};
-
+
CLLocationCoordinate2D interiorCoordinates[] = {
CLLocationCoordinate2DMake(100.2, 0.2),
CLLocationCoordinate2DMake(100.8, 0.2),
CLLocationCoordinate2DMake(100.8, 0.8),
CLLocationCoordinate2DMake(100.2, 0.8),
CLLocationCoordinate2DMake(100.2, 0.2)};
-
+
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:interiorCoordinates count:5];
-
+
MGLPolygonFeature *polygonFeature = [MGLPolygonFeature polygonWithCoordinates:coordinates count:5 interiorPolygons:@[polygon]];
-
+
CLLocationCoordinate2D coordinates_2[] = { CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(10, 10)};
MGLPolylineFeature *polylineFeature = [MGLPolylineFeature polylineWithCoordinates:coordinates_2 count:2];
-
+
MGLMultiPolygonFeature *multiPolygonFeature = [MGLMultiPolygonFeature multiPolygonWithPolygons:@[polygonFeature, polygonFeature]];
-
+
MGLMultiPolylineFeature *multiPolylineFeature = [MGLMultiPolylineFeature multiPolylineWithPolylines:@[polylineFeature, polylineFeature]];
-
+
MGLPointCollectionFeature *pointCollectionFeature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:5];
-
+
MGLPointFeature *pointFeature = [MGLPointFeature new];
pointFeature.coordinate = CLLocationCoordinate2DMake(100.2, 0.2);
-
+
MGLShapeCollectionFeature *shapeCollectionFeature = [MGLShapeCollectionFeature shapeCollectionWithShapes:@[polygonFeature, polylineFeature, multiPolygonFeature, multiPolylineFeature, pointCollectionFeature, pointFeature]];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"source-id" shape:shapeCollectionFeature options:nil];
-
+
MGLShapeCollectionFeature *shape = (MGLShapeCollectionFeature *)source.shape;
XCTAssertNotNil(shape);
XCTAssert(shape.shapes.count == 6, @"Shape collection should contain 6 shapes");
diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m
index 1dba9f4305..b51fa02af4 100644
--- a/platform/darwin/test/MGLStyleLayerTests.m
+++ b/platform/darwin/test/MGLStyleLayerTests.m
@@ -11,22 +11,22 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertEqualObjects(layer.identifier, @"layerID");
XCTAssertEqualObjects(layer.sourceIdentifier, source.identifier);
-
+
XCTAssertTrue(layer.visible);
layer.visible = NO;
XCTAssertFalse(layer.visible);
layer.visible = YES;
XCTAssertTrue(layer.visible);
-
+
XCTAssertEqual(layer.minimumZoomLevel, -INFINITY);
layer.minimumZoomLevel = 22;
XCTAssertEqual(layer.minimumZoomLevel, 22);
-
+
XCTAssertEqual(layer.maximumZoomLevel, INFINITY);
layer.maximumZoomLevel = 0;
XCTAssertEqual(layer.maximumZoomLevel, 0);
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
index 00842a5b4e..810d7fbd3b 100644
--- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -3,8 +3,8 @@
const properties = locals.properties;
const enumProperties = locals.enumProperties;
-%>
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -26,13 +26,13 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
-
+
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
@@ -47,48 +47,83 @@
<% } else { -%>
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGL<%- camelize(type) %>StyleLayer *layer = [[MGL<%- camelize(type) %>StyleLayer alloc] initWithIdentifier:@"layerID" source:source];
<% } -%>
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::<%- camelize(type) %>Layer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::<%- camelize(type) %>Layer>();
<% for (const property of properties) { -%>
-
+
// <%- originalPropertyName(property) %>
{
XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
@"<%- originalPropertyName(property) %> should be unset initially.");
MGLStyleValue<<%- propertyType(property) %>> *defaultStyleValue = layer.<%- objCName(property) %>;
-
- MGLStyleValue<<%- propertyType(property) %>> *styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>];
- layer.<%- objCName(property) %> = styleValue;
+
+ MGLStyleValue<<%- propertyType(property) %>> *constantStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithRawValue:<%- objCTestValue(property, type, 3) %>];
+ layer.<%- objCName(property) %> = constantStyleValue;
+<% if (property["property-function"]) { -%>
+ mbgl::style::DataDrivenPropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
+<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
+<% } -%>
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
@"Setting <%- objCName(property) %> to a constant value should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue,
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, constantStyleValue,
@"<%- objCName(property) %> should round-trip constant values.");
+
+ MGLStyleValue<<%- propertyType(property) %>> * functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.<%- objCName(property) %> = functionStyleValue;
+
+ mbgl::style::IntervalStops<<%- mbglType(property) %>> intervalStops = { {{18, <%- mbglTestValue(property, type) %>}} };
+ propertyValue = mbgl::style::CameraFunction<<%- mbglType(property) %>> { intervalStops };
- styleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithStops:@{
- @18: styleValue,
- }];
- layer.<%- objCName(property) %> = styleValue;
- propertyValue = { mbgl::style::Function<<%- mbglType(property) %>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
- @"Setting <%- objCName(property) %> to a function should update <%- originalPropertyName(property) %>.");
- XCTAssertEqualObjects(layer.<%- objCName(property) %>, styleValue,
- @"<%- objCName(property) %> should round-trip functions.");
+ @"Setting <%- objCName(property) %> to a camera function should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
+ @"<%- objCName(property) %> should round-trip camera functions.");
+
+<% if (property["property-function"] && isInterpolatable(property)) { -%>
+ functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.<%- objCName(property) %> = functionStyleValue;
+
+ mbgl::style::ExponentialStops<<%- mbglType(property) %>> exponentialStops = { {{18, <%- mbglTestValue(property, type) %>}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<<%- mbglType(property) %>> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
+ @"Setting <%- objCName(property) %> to a source function should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
+ @"<%- objCName(property) %> should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.<%- objCName(property) %> = functionStyleValue;
+
+ std::map<float, <%- mbglType(property) %>> innerStops { {18, <%- mbglTestValue(property, type) %>} };
+ mbgl::style::CompositeExponentialStops<<%- mbglType(property) %>> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<<%- mbglType(property) %>> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
+ @"Setting <%- objCName(property) %> to a composite function should update <%- originalPropertyName(property) %>.");
+ XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionStyleValue,
+ @"<%- objCName(property) %> should round-trip composite functions.");
+<% } -%>
<% if (!property.required) { -%>
-
+
layer.<%- objCName(property) %> = nil;
XCTAssertTrue(rawLayer->get<%- camelize(originalPropertyName(property)) %>().isUndefined(),
@"Unsetting <%- objCName(property) %> should return <%- originalPropertyName(property) %> to the default value.");
XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultStyleValue,
@"<%- objCName(property) %> should return the default value after being unset.");
<% } -%>
+<% if (!property["property-function"]) { -%>
+
+ functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<<%- propertyType(property) %>> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+<% } -%>
}
<% } -%>
}
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index 176217619d..36772e556d 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -25,7 +25,7 @@
- (void)setUp {
[super setUp];
-
+
[MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"];
NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"];
self.mapView = [[MGLMapView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) styleURL:styleURL];
@@ -39,14 +39,14 @@
- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
XCTAssertNotNil(mapView.style);
XCTAssertEqual(mapView.style, style);
-
+
[_styleLoadingExpectation fulfill];
}
- (void)tearDown {
_styleLoadingExpectation = nil;
self.mapView = nil;
-
+
[super tearDown];
}
@@ -81,7 +81,7 @@
XCTAssertEqualObjects([MGLStyle satelliteStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/satellite-v99");
XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion].absoluteString, @(mbgl::util::default_styles::satelliteStreets.url));
XCTAssertEqualObjects([MGLStyle satelliteStreetsStyleURLWithVersion:99].absoluteString, @"mapbox://styles/mapbox/satellite-streets-v99");
-
+
static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
"MGLStyleTests isn’t testing all the styles in mbgl::util::default_styles.");
}
@@ -109,17 +109,17 @@
XCTAssertEqual(mbgl::util::default_styles::numOrderedStyles, numVersionedMethods,
@"There are %lu default styles but MGLStyleTests only provides versioned style URL methods for %u of them.",
mbgl::util::default_styles::numOrderedStyles, numVersionedMethods);
-
+
// Test that all the versioned style methods are in the public header.
NSString *styleHeader = self.stringWithContentsOfStyleHeader;
-
+
NSError *versionedMethodError;
NSString *versionedMethodExpressionString = @(R"RE(^\+\s*\(NSURL\s*\*\s*\)\s*\w+StyleURLWithVersion\s*:\s*\(\s*NSInteger\s*\)\s*version\s*;)RE");
NSRegularExpression *versionedMethodExpression = [NSRegularExpression regularExpressionWithPattern:versionedMethodExpressionString options:NSRegularExpressionAnchorsMatchLines error:&versionedMethodError];
XCTAssertNil(versionedMethodError, @"Error compiling regular expression to search for versioned methods.");
NSUInteger numVersionedMethodDeclarations = [versionedMethodExpression numberOfMatchesInString:styleHeader options:0 range:NSMakeRange(0, styleHeader.length)];
XCTAssertEqual(numVersionedMethodDeclarations, numVersionedMethods);
-
+
// Test that “current version is” statements are present and current for all versioned style methods.
NSError *versionError;
NSString *versionExpressionString = @(R"RE(current version is `(\d+)`)RE");
@@ -174,6 +174,58 @@
XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException");
}
+- (void)testRemovingSourcesBeforeAddingThem {
+ MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"raster-source" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:rasterSource];
+ [self.style addSource:rasterSource];
+ XCTAssertNotNil([self.style sourceWithIdentifier:rasterSource.identifier]);
+
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source" shape:nil options:nil];
+ [self.style removeSource:shapeSource];
+ [self.style addSource:shapeSource];
+ XCTAssertNotNil([self.style sourceWithIdentifier:shapeSource.identifier]);
+
+ MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"vector-source" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:vectorSource];
+ [self.style addSource:vectorSource];
+ XCTAssertNotNil([self.style sourceWithIdentifier:vectorSource.identifier]);
+}
+
+- (void)testAddingSourceOfTypeABeforeSourceOfTypeBWithSameIdentifier {
+ // Add a raster source
+ MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style addSource:rasterSource];
+
+ // Attempt to remove a shape source with the same identifier as the raster source
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"some-identifier" shape:nil options:nil];
+ [self.style removeSource:shapeSource];
+ // The raster source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
+
+ // Remove the raster source
+ [self.style removeSource:rasterSource];
+
+ // Add the shape source
+ [self.style addSource:shapeSource];
+
+ // Attempt to remove a vector source with the same identifer as the shape source
+ MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
+ [self.style removeSource:vectorSource];
+ // The shape source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLShapeSource class]]);
+
+ // Remove the shape source
+ [self.style removeSource:shapeSource];
+
+ // Add the vector source
+ [self.style addSource:vectorSource];
+
+ // Attempt to remove the previously created raster source that has the same identifer as the shape source
+ [self.style removeSource:rasterSource];
+ // The vector source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
+}
+
- (void)testLayers {
NSArray<MGLStyleLayer *> *initialLayers = self.style.layers;
if ([initialLayers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) {
@@ -219,15 +271,15 @@
}
- (void)testAddingLayersWithDuplicateIdentifiers {
- //Just some source
+ // Just some source
MGLVectorSource *source = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
[self.style addSource: source];
-
- //Add initial layer
+
+ // Add initial layer
MGLFillStyleLayer *initial = [[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source];
[self.style addLayer:initial];
-
- //Try to add the duplicate
+
+ // Try to add the duplicate
XCTAssertThrowsSpecificNamed([self.style addLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source]], NSException, @"MGLRedundantLayerIdentifierException");
XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] belowLayer:initial],NSException, @"MGLRedundantLayerIdentifierException");
XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLFillStyleLayer alloc] initWithIdentifier:@"my-layer" source:source] aboveLayer:initial], NSException, @"MGLRedundantLayerIdentifierException");
@@ -235,6 +287,58 @@
XCTAssertThrowsSpecificNamed([self.style insertLayer:[[MGLOpenGLStyleLayer alloc] initWithIdentifier:@"my-layer"] atIndex:0], NSException, @"MGLRedundantLayerIdentifierException");
}
+- (void)testRemovingLayerBeforeAddingSameLayer {
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-removing-before-adding" shape:nil options:nil];
+
+ // Attempting to find a layer with identifier will trigger an exception if the source associated with the layer is not added
+ [self.style addSource:source];
+
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:source];
+ [self.style removeLayer:fillLayer];
+ [self.style addLayer:fillLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:fillLayer.identifier]);
+
+ MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"raster-layer" source:source];
+ [self.style removeLayer:rasterLayer];
+ [self.style addLayer:rasterLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:rasterLayer.identifier]);
+
+ MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbol-layer" source:source];
+ [self.style removeLayer:symbolLayer];
+ [self.style addLayer:symbolLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:symbolLayer.identifier]);
+
+ MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"line-layer" source:source];
+ [self.style removeLayer:lineLayer];
+ [self.style addLayer:lineLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:lineLayer.identifier]);
+
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circle-layer" source:source];
+ [self.style removeLayer:circleLayer];
+ [self.style addLayer:circleLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:circleLayer.identifier]);
+
+ MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"background-layer"];
+ [self.style removeLayer:backgroundLayer];
+ [self.style addLayer:backgroundLayer];
+ XCTAssertNotNil([self.style layerWithIdentifier:backgroundLayer.identifier]);
+}
+
+- (void)testAddingLayerOfTypeABeforeRemovingLayerOfTypeBWithSameIdentifier {
+ MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source-identifier" shape:nil options:nil];
+ [self.style addSource:source];
+
+ // Add a fill layer
+ MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"some-identifier" source:source];
+ [self.style addLayer:fillLayer];
+
+ // Attempt to remove a line layer with the same identifier as the fill layer
+ MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:fillLayer.identifier source:source];
+ [self.style removeLayer:lineLayer];
+
+ XCTAssertTrue([[self.style layerWithIdentifier:fillLayer.identifier] isMemberOfClass:[MGLFillStyleLayer class]]);
+}
+
- (NSString *)stringWithContentsOfStyleHeader {
NSURL *styleHeaderURL = [[[NSBundle mgl_frameworkBundle].bundleURL
URLByAppendingPathComponent:@"Headers" isDirectory:YES]
@@ -246,7 +350,10 @@
}
- (void)testClasses {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
XCTAssertEqual(self.style.styleClasses.count, 0);
+#pragma clang diagnostic pop
}
- (void)testImages {
@@ -259,10 +366,10 @@
MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
#endif
XCTAssertNotNil(image);
-
+
[self.style setImage:image forName:imageName];
MGLImage *styleImage = [self.style imageForName:imageName];
-
+
XCTAssertNotNil(styleImage);
XCTAssertEqual(image.size.width, styleImage.size.width);
XCTAssertEqual(image.size.height, styleImage.size.height);
@@ -273,28 +380,28 @@
NSURL *url = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" URL:url options:nil];
[self.style addSource:source];
-
+
MGLCircleStyleLayer *layer1 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer1" source:source];
[self.style addLayer:layer1];
-
+
MGLCircleStyleLayer *layer3 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer3" source:source];
[self.style addLayer:layer3];
-
+
MGLCircleStyleLayer *layer2 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer2" source:source];
[self.style insertLayer:layer2 aboveLayer:layer1];
-
+
MGLCircleStyleLayer *layer4 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer4" source:source];
[self.style insertLayer:layer4 aboveLayer:layer3];
-
+
MGLCircleStyleLayer *layer0 = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"layer0" source:source];
[self.style insertLayer:layer0 belowLayer:layer1];
-
+
NSArray<MGLStyleLayer *> *layers = [self.style layers];
NSUInteger startIndex = 0;
if ([layers.firstObject.identifier isEqualToString:@"com.mapbox.annotations.points"]) {
startIndex++;
}
-
+
XCTAssertEqualObjects(layers[startIndex++].identifier, layer0.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer1.identifier);
XCTAssertEqualObjects(layers[startIndex++].identifier, layer2.identifier);
diff --git a/platform/darwin/test/MGLStyleValueTests.m b/platform/darwin/test/MGLStyleValueTests.m
index fe6096584d..cd6eec8324 100644
--- a/platform/darwin/test/MGLStyleValueTests.m
+++ b/platform/darwin/test/MGLStyleValueTests.m
@@ -7,7 +7,107 @@
@implementation MGLStyleValueTests
- (void)testStoplessFunction {
- XCTAssertThrowsSpecificNamed([MGLStyleValue<NSNumber *> valueWithStops:@{}], NSException, NSInvalidArgumentException, @"Stopless function should raise an exception");
+ XCTAssertThrowsSpecificNamed([MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{} options:nil], NSException, NSInvalidArgumentException, @"Stopless function should raise an exception");
+}
+
+- (void)testDeprecatedFunctions {
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"test"
+ shape:nil
+ options:nil];
+ MGLSymbolStyleLayer *symbolStyleLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbolLayer"
+ source:shapeSource];
+ MGLCircleStyleLayer *circleStyleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayer"
+ source:shapeSource];
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ // deprecated function, stops with float values
+ NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *stops = @{
+ @1: [MGLStyleValue<NSNumber *> valueWithRawValue:@0],
+ @2: [MGLStyleValue<NSNumber *> valueWithRawValue:@1],
+ @3: [MGLStyleValue<NSNumber *> valueWithRawValue:@2],
+ @4: [MGLStyleValue<NSNumber *> valueWithRawValue:@0],
+ };
+ MGLStyleValue<NSNumber *> *iconHaloBlurStyleValue =
+ [MGLStyleValue<NSNumber *> valueWithInterpolationBase:1.0 stops:stops];
+ symbolStyleLayer.iconHaloBlur = iconHaloBlurStyleValue;
+ XCTAssertEqualObjects(symbolStyleLayer.iconHaloBlur, iconHaloBlurStyleValue);
+
+ // deprecated function, stops with boolean values
+ stops = @{
+ @1: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
+ @2: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
+ @3: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
+ @4: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
+ };
+ MGLStyleValue<NSNumber *> *iconAllowsOverlapStyleValue =
+ [MGLStyleValue<NSNumber *> valueWithInterpolationBase:1.0 stops:stops];
+ symbolStyleLayer.iconAllowsOverlap = iconAllowsOverlapStyleValue;
+ // iconAllowsOverlap is boolean so mgl and mbgl conversions will coerce the developers stops into interval stops
+ MGLStyleValue<NSNumber *> *expectedIconAllowsOverlapStyleValue =
+ [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval
+ cameraStops:stops
+ options:nil];
+ XCTAssertEqualObjects(symbolStyleLayer.iconAllowsOverlap, expectedIconAllowsOverlapStyleValue);
+
+ ///
+ // creating and using MGLStyleFunctions directly
+ ///
+
+ NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *circleRadiusStops = @{
+ @0: [MGLStyleValue<NSNumber *> valueWithRawValue:@10],
+ @20: [MGLStyleValue<NSNumber *> valueWithRawValue:@5],
+ };
+ MGLStyleFunction<NSNumber *> *circleRadiusFunction =
+ [MGLStyleFunction<NSNumber *> functionWithInterpolationBase:1.0
+ stops:circleRadiusStops];
+ circleStyleLayer.circleRadius = circleRadiusFunction;
+ MGLStyleValue<NSNumber *> *expectedCircleRadiusFunction =
+ [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:circleRadiusStops
+ options:nil];
+ // setting a data driven property to an MGLStyleFunction should return an exponential camera function
+ XCTAssertEqualObjects(circleStyleLayer.circleRadius, expectedCircleRadiusFunction);
+
+ CGVector circleTranslationOne = CGVectorMake(100, 0);
+ CGVector circleTranslationTwo = CGVectorMake(0, 0);
+#if TARGET_OS_IPHONE
+ NSValue *circleTranslationValueOne = [NSValue valueWithCGVector:circleTranslationOne];
+ NSValue *circleTranslationValueTwo = [NSValue valueWithCGVector:circleTranslationTwo];
+#else
+ NSValue *circleTranslationValueOne = [NSValue value:&circleTranslationOne withObjCType:@encode(CGVector)];
+ NSValue *circleTranslationValueTwo = [NSValue value:&circleTranslationTwo withObjCType:@encode(CGVector)];
+#endif
+
+ NSDictionary<NSNumber *, MGLStyleValue<NSValue *> *> *circleTranslationStops = @{
+ @0: [MGLStyleValue<NSValue *> valueWithRawValue:circleTranslationValueOne],
+ @10: [MGLStyleValue<NSValue *> valueWithRawValue:circleTranslationValueTwo],
+ };
+ MGLStyleFunction<NSValue *> *circleTranslationFunction =
+ [MGLStyleFunction<NSValue *> functionWithInterpolationBase:1.0
+ stops:circleTranslationStops];
+ circleStyleLayer.circleTranslation = circleTranslationFunction;
+ MGLStyleValue<NSValue *> *expectedCircleTranslationFunction =
+ [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:circleTranslationStops
+ options:nil];
+ // setting a non-data driven, interpolatable property to an MGLStyleFunction should return an exponential camera function
+ XCTAssertEqualObjects(circleStyleLayer.circleTranslation, expectedCircleTranslationFunction);
+
+ NSDictionary<NSNumber *, MGLStyleValue<NSNumber *> *> *iconOptionalStops = @{
+ @0: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
+ @20: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
+ };
+ MGLStyleFunction<NSNumber *> *iconOptionalFunction =
+ [MGLStyleFunction<NSNumber *> valueWithInterpolationBase:1.0
+ stops:iconOptionalStops];
+ symbolStyleLayer.iconOptional = iconOptionalFunction;
+ MGLStyleValue<NSNumber *> *expectedIconOptionalFunction =
+ [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval
+ cameraStops:iconOptionalStops
+ options:nil];
+ XCTAssertEqualObjects(symbolStyleLayer.iconOptional, expectedIconOptionalFunction);
+#pragma clang diagnostic pop
}
@end
diff --git a/platform/darwin/test/MGLStyleValueTests.swift b/platform/darwin/test/MGLStyleValueTests.swift
index 18b6a901de..f965c31e40 100644
--- a/platform/darwin/test/MGLStyleValueTests.swift
+++ b/platform/darwin/test/MGLStyleValueTests.swift
@@ -1,12 +1,93 @@
import XCTest
import Mapbox
-
+#if os(iOS) || os(watchOS) || os(tvOS)
+typealias MGLColor = UIColor
+#elseif os(macOS)
+typealias MGLColor = NSColor
+#endif
+
extension MGLStyleValueTests {
+ func assertColorsEqualWithAccuracy(_ actual: MGLColor, _ expected: MGLColor, accuracy: Float = 1/255) {
+ var actualComponents : [CGFloat] = [0, 0, 0, 0]
+ var expectedComponents : [CGFloat] = [0, 0, 0, 0]
+ actual.getRed(&(actualComponents[0]), green: &(actualComponents[1]), blue: &(actualComponents[2]), alpha: &(actualComponents[3]))
+ expected.getRed(&(expectedComponents[0]), green: &(expectedComponents[1]), blue: &(expectedComponents[2]), alpha: &(expectedComponents[3]))
+ for (ac, ec) in zip(actualComponents, expectedComponents) {
+ XCTAssertEqualWithAccuracy(Float(ac), Float(ec), accuracy: accuracy)
+ }
+ }
+
+ func assertColorValuesEqual(_ actual: MGLStyleValue<MGLColor>, _ expected: MGLStyleValue<MGLColor>) {
+ guard type(of: actual) == type(of: expected) else {
+ XCTFail("Expected \(type(of: expected)), but found \(type(of: actual)) instead.")
+ return
+ }
+
+ if let actualConstant = actual as? MGLStyleConstantValue<MGLColor> {
+ assertColorsEqualWithAccuracy(actualConstant.rawValue, (expected as! MGLStyleConstantValue<MGLColor>).rawValue)
+ } else if let actualFunction = actual as? MGLStyleFunction<MGLColor>,
+ let expectedFunction = expected as? MGLStyleFunction<MGLColor> {
+
+ // unless we have stops, there's no need for a custom comparison - default to plain == assertion
+ guard let actualStops = actualFunction.stops, let expectedStops = expectedFunction.stops else {
+ XCTAssertEqual(actualFunction, expectedFunction)
+ return
+ }
+
+ guard expectedStops is [String: Any] || expectedStops is [Float:Any] else {
+ XCTFail("Stop levels must be String or Float.")
+ return
+ }
+
+ XCTAssertEqual(actualFunction.interpolationBase, expectedFunction.interpolationBase)
+ XCTAssertEqual(actualFunction.interpolationMode, expectedFunction.interpolationMode)
+ if let actualFunction = actualFunction as? MGLSourceStyleFunction<MGLColor>,
+ let expectedFunction = expectedFunction as? MGLSourceStyleFunction<MGLColor> {
+ XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
+ } else if let actualFunction = actualFunction as? MGLCompositeStyleFunction<MGLColor>,
+ let expectedFunction = expectedFunction as? MGLCompositeStyleFunction<MGLColor> {
+ XCTAssertEqual(actualFunction.defaultValue, expectedFunction.defaultValue)
+ }
+
+ func assertStopEqual (_ actualValue: Any?, _ expectedValue: Any?) {
+ guard type(of: actualValue) == type(of: expectedValue) else {
+ XCTFail("Expected stop value of type \(type(of: expectedValue)), but found \(type(of: actualValue)) instead.")
+ return
+ }
+ if let actualValue = actualValue as? MGLStyleConstantValue<MGLColor>,
+ let expectedValue = expectedValue as? MGLStyleConstantValue<MGLColor> {
+ assertColorsEqualWithAccuracy(actualValue.rawValue, expectedValue.rawValue)
+ } else if let actualValue = actualValue as? MGLStyleConstantValue<AnyObject>,
+ let expectedValue = expectedValue as? MGLStyleConstantValue<AnyObject> {
+ XCTAssertEqual(actualValue, expectedValue)
+ } else {
+ XCTFail("Unsupported stop value type \(type(of: actualValue)).")
+ }
+ }
+
+ XCTAssertEqual(actualStops.count, expectedStops.count)
+ if let actualStops = actualStops as? [String:Any], let expectedStops = expectedStops as? [String: Any] {
+ for (key, value) in actualStops {
+ assertStopEqual(value, expectedStops[key])
+ }
+ } else if let actualStops = actualStops as? [Float:Any], let expectedStops = expectedStops as? [Float:Any] {
+ for (key, value) in actualStops {
+ assertStopEqual(value, expectedStops[key])
+ }
+ } else {
+ XCTFail("Expected stops of type \(type(of: Array(expectedStops.keys)).Index.self), but found \(type(of: Array(actualStops.keys)).Index.self) instead.")
+ return
+ }
+ } else {
+ XCTFail("MGLStyleValue<MGLColor> must be either a constant or a style function.")
+ }
+ }
func testConstantValues() {
- let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
- let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: shapeSource)
+ let shapeSource = MGLShapeSource(identifier: "source", shape: nil, options: nil)
+ let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "symbolLayer", source: shapeSource)
+ let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
// Boolean
symbolStyleLayer.iconAllowsOverlap = MGLStyleConstantValue(rawValue: true)
@@ -19,20 +100,198 @@ extension MGLStyleValueTests {
// String
symbolStyleLayer.text = MGLStyleConstantValue(rawValue: "{name}")
XCTAssertEqual((symbolStyleLayer.text as! MGLStyleConstantValue<NSString>).rawValue, "{name}")
+
+ var circleTranslationOne = CGVector(dx: 100, dy: 0)
+ let circleTranslationValueOne = NSValue(bytes: &circleTranslationOne, objCType: "{CGVector=dd}")
+
+ // non-data-driven (interpolatable property value), set to constant style value
+ let expectedCircleTranslationValue = MGLStyleValue<NSValue>(rawValue: circleTranslationValueOne)
+ circleStyleLayer.circleTranslation = expectedCircleTranslationValue
+ XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue)
+
+ // non-data-driven (enumeration property value), set to constant style value
+ let expectedCircleScaleAlignmentValue = MGLStyleValue<NSValue>(rawValue: NSValue(mglCircleScaleAlignment: .map))
+ circleStyleLayer.circleScaleAlignment = expectedCircleScaleAlignmentValue
+ XCTAssertEqual(circleStyleLayer.circleScaleAlignment, expectedCircleScaleAlignmentValue)
}
-
- func testFunctions() {
+
+ func testFunctionsWithNonDataDrivenProperties() {
+ let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
+ let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
+
+ var circleTranslationOne = CGVector(dx: 100, dy: 0)
+ let circleTranslationValueOne = NSValue(bytes: &circleTranslationOne, objCType: "{CGVector=dd}")
+ var circleTranslationTwo = CGVector(dx: 0, dy: 0)
+ let circleTranslationValueTwo = NSValue(bytes: &circleTranslationTwo, objCType: "{CGVector=dd}")
+
+ let circleTranslationStops : [Float:MGLStyleValue<NSValue>] = [
+ 0: MGLStyleValue<NSValue>(rawValue: circleTranslationValueOne),
+ 10: MGLStyleValue<NSValue>(rawValue: circleTranslationValueTwo)
+ ]
+
+ // non-data-driven (interpolatable property value), camera function with CGVector (NSValue) stop values
+ let expectedCircleTranslationValue = MGLStyleValue<NSValue>(
+ interpolationMode: .interval,
+ cameraStops: circleTranslationStops,
+ options: nil
+ )
+ circleStyleLayer.circleTranslation = expectedCircleTranslationValue
+ XCTAssertEqual(circleStyleLayer.circleTranslation, expectedCircleTranslationValue)
+
+ // non-data-driven (enumeration property value), camera function with MGLCircleScaleAlignment enum (NSValue) stop values
+ let scaleAlignmentStops : [Float:MGLStyleValue<NSValue>] = [
+ 0: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .map)),
+ 10: MGLStyleValue(rawValue: NSValue(mglCircleScaleAlignment: .viewport))
+ ]
+ let expectedCircleScaleAlignmentValue = MGLStyleValue<NSValue>(
+ interpolationMode: .interval,
+ cameraStops: scaleAlignmentStops,
+ options: nil
+ )
+ circleStyleLayer.circleScaleAlignment = expectedCircleScaleAlignmentValue
+ XCTAssertEqual(circleStyleLayer.circleScaleAlignment, expectedCircleScaleAlignmentValue)
+ }
+
+ func testFunctionsWithDataDrivenProperties() {
let shapeSource = MGLShapeSource(identifier: "test", shape: nil, options: nil)
- let symbolStyleLayer = MGLSymbolStyleLayer(identifier: "test", source: shapeSource)
+ let circleStyleLayer = MGLCircleStyleLayer(identifier: "circleLayer", source: shapeSource)
- // Boolean
- let stops: [NSNumber: MGLStyleValue<NSNumber>] = [
- 1: MGLStyleValue(rawValue: true),
- 2: MGLStyleValue(rawValue: false),
- 3: MGLStyleValue(rawValue: true),
- 4: MGLStyleValue(rawValue: false),
- ]
- symbolStyleLayer.iconAllowsOverlap = MGLStyleFunction<NSNumber>(interpolationBase: 1, stops: stops)
- XCTAssertEqual((symbolStyleLayer.iconAllowsOverlap as! MGLStyleFunction<NSNumber>), MGLStyleFunction(interpolationBase: 1, stops: stops))
+ // data-driven, camera function with exponential color stop values
+ let redGreenStops : [Float:MGLStyleValue<MGLColor>] = [
+ 0: MGLStyleValue<MGLColor>(rawValue: .red),
+ 10: MGLStyleValue<MGLColor>(rawValue: .red),
+ 15: MGLStyleValue<MGLColor>(rawValue: .green)
+ ]
+ let expectedCircleColorValue = MGLStyleValue<MGLColor>(
+ interpolationMode: .exponential,
+ cameraStops: redGreenStops,
+ options: [.interpolationBase: 10.0]
+ )
+ circleStyleLayer.circleColor = expectedCircleColorValue
+ assertColorValuesEqual(circleStyleLayer.circleColor as! MGLStyleFunction<MGLColor>, expectedCircleColorValue as! MGLStyleFunction<MGLColor>)
+
+ // data-driven, source function with categorical color stop values with string attribute keys
+ let redOnlyStops = [
+ "red": MGLStyleValue<MGLColor>(rawValue: .red)
+ ]
+ let expectedRedCategoricalValue = MGLStyleValue<MGLColor>(
+ interpolationMode: .categorical,
+ sourceStops: redOnlyStops,
+ attributeName: "red",
+ options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .cyan)]
+ )
+ circleStyleLayer.circleColor = expectedRedCategoricalValue
+ assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedCategoricalValue)
+
+ // data-driven, source function with categorical color stop values with integer attribute keys
+ let greenOrangeStops : [Float:MGLStyleValue<MGLColor>] = [
+ 0: MGLStyleValue<MGLColor>(rawValue: .green),
+ 100: MGLStyleValue<MGLColor>(rawValue: .orange)
+ ]
+ let expectedGreenOrangeCategoricalValue = MGLStyleValue<MGLColor>(
+ interpolationMode: .categorical,
+ sourceStops: greenOrangeStops,
+ attributeName: "temp",
+ options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .red)]
+ )
+ circleStyleLayer.circleColor = expectedGreenOrangeCategoricalValue
+ assertColorValuesEqual(circleStyleLayer.circleColor, expectedGreenOrangeCategoricalValue)
+
+ // data-driven, source function with exponential color stop values
+ let expectedRedGreenSourceExponentialValue = MGLStyleValue<MGLColor>(
+ interpolationMode: .exponential,
+ sourceStops: redGreenStops,
+ attributeName: "temp",
+ options: nil
+ )
+ circleStyleLayer.circleColor = expectedRedGreenSourceExponentialValue
+ assertColorValuesEqual(circleStyleLayer.circleColor, expectedRedGreenSourceExponentialValue)
+
+ // data-driven, identity source function
+ let expectedSourceIdentityValue = MGLStyleValue<MGLColor>(
+ interpolationMode: .identity,
+ sourceStops: nil,
+ attributeName: "size",
+ options: [.defaultValue: MGLStyleValue<MGLColor>(rawValue: .green)]
+ )
+ circleStyleLayer.circleColor = expectedSourceIdentityValue
+ assertColorValuesEqual(circleStyleLayer.circleColor, expectedSourceIdentityValue)
+
+ // data-driven, source function with categorical color stop values with boolean attribute keys
+ let booleanCategoricalStops = [
+ false: MGLStyleValue<NSNumber>(rawValue: 0),
+ true: MGLStyleValue<NSNumber>(rawValue: 2)
+ ]
+ let expectedCircleBlurCategoricalValue = MGLStyleValue<NSNumber>(
+ interpolationMode: .categorical,
+ sourceStops: booleanCategoricalStops,
+ attributeName: "fuzzy",
+ options: [.defaultValue: MGLStyleValue<NSNumber>(rawValue: 42)]
+ )
+ circleStyleLayer.circleBlur = expectedCircleBlurCategoricalValue
+ XCTAssertEqual(circleStyleLayer.circleBlur, expectedCircleBlurCategoricalValue)
+
+ // data-driven, composite function with inner categorical color stop values with string attribute keys nested in outer camera stops
+ let smallRadius = MGLStyleValue<NSNumber>(rawValue: 5)
+ let mediumRadius = MGLStyleValue<NSNumber>(rawValue: 10)
+ let largeRadius = MGLStyleValue<NSNumber>(rawValue: 20)
+ let radiusCompositeCategoricalStops: [Float: [String: MGLStyleValue<NSNumber>]] = [
+ 0: ["green": smallRadius],
+ 10: ["green": smallRadius],
+ 15: ["green": largeRadius],
+ 20: ["green": largeRadius]
+ ]
+ let defaultRadius = MGLStyleValue<NSNumber>(rawValue: 2)
+ let expectedCompositeCategoricalValue = MGLStyleValue<NSNumber>(
+ interpolationMode: .categorical,
+ compositeStops: radiusCompositeCategoricalStops,
+ attributeName: "color",
+ options: [.defaultValue: defaultRadius]
+ )
+ circleStyleLayer.circleRadius = expectedCompositeCategoricalValue
+ XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeCategoricalValue)
+
+ // data-driven, composite function with inner exponential color stop values nested in outer camera stops
+ let radiusCompositeExponentialOrIntervalStops: [Float: [Float: MGLStyleValue<NSNumber>]] = [
+ 0: [0: smallRadius],
+ 10: [200: smallRadius],
+ 20: [200: largeRadius]
+ ]
+ let expectedCompositeExponentialValue = MGLStyleValue<NSNumber>(
+ interpolationMode: .exponential,
+ compositeStops: radiusCompositeExponentialOrIntervalStops,
+ attributeName: "temp",
+ options: [.defaultValue: mediumRadius]
+ )
+ circleStyleLayer.circleRadius = expectedCompositeExponentialValue
+ XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeExponentialValue)
+
+ // get a value back
+ if let returnedCircleRadius = circleStyleLayer.circleRadius as? MGLCompositeStyleFunction<NSNumber> {
+ if let returnedStops = returnedCircleRadius.stops as NSDictionary? as? [NSNumber: [NSNumber: MGLStyleValue<NSNumber>]] {
+ let lhs: MGLStyleValue<NSNumber> = returnedStops[0]!.values.first!
+ let rhs: MGLStyleValue<NSNumber> = radiusCompositeExponentialOrIntervalStops[0]!.values.first!
+ XCTAssertEqual(lhs, rhs)
+ }
+ }
+
+ // get value back as base class
+ if let returnedCircleRadius = circleStyleLayer.circleRadius as? MGLStyleFunction<NSNumber> {
+ if let returnedStops = returnedCircleRadius.stops as NSDictionary? as? [NSNumber: [NSNumber: MGLStyleValue<NSNumber>]] {
+ let lhs: MGLStyleValue<NSNumber> = returnedStops[0]!.values.first!
+ let rhs: MGLStyleValue<NSNumber> = radiusCompositeExponentialOrIntervalStops[0]!.values.first!
+ XCTAssertEqual(lhs, rhs)
+ }
+ }
+
+ // data-driven, composite function with inner interval color stop values nested in outer camera stops
+ let expectedCompositeIntervalValue = MGLStyleValue<NSNumber>(
+ interpolationMode: .interval,
+ compositeStops: radiusCompositeExponentialOrIntervalStops,
+ attributeName: "temp",
+ options: nil
+ )
+ circleStyleLayer.circleRadius = expectedCompositeIntervalValue
+ XCTAssertEqual(circleStyleLayer.circleRadius, expectedCompositeIntervalValue)
}
}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index 80a9c9d3ec..1d599f5aca 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -1,5 +1,5 @@
-// This file is generated.
-// Edit platform/darwin/scripts/generate-style-code.js, then run `make style-code-darwin`.
+// This file is generated.
+// Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`.
#import "MGLStyleLayerTests.h"
@@ -20,13 +20,13 @@
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
-
+
XCTAssertNil(layer.sourceLayerIdentifier);
layer.sourceLayerIdentifier = @"layerID";
XCTAssertEqualObjects(layer.sourceLayerIdentifier, @"layerID");
layer.sourceLayerIdentifier = nil;
XCTAssertNil(layer.sourceLayerIdentifier);
-
+
XCTAssertNil(layer.predicate);
layer.predicate = [NSPredicate predicateWithValue:NO];
XCTAssertEqualObjects(layer.predicate, [NSPredicate predicateWithValue:NO]);
@@ -37,1672 +37,2118 @@
- (void)testProperties {
MGLPointFeature *feature = [[MGLPointFeature alloc] init];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"sourceID" shape:feature options:nil];
-
+
MGLSymbolStyleLayer *layer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"layerID" source:source];
XCTAssertNotEqual(layer.rawLayer, nullptr);
XCTAssertTrue(layer.rawLayer->is<mbgl::style::SymbolLayer>());
auto rawLayer = layer.rawLayer->as<mbgl::style::SymbolLayer>();
-
+
// icon-allow-overlap
{
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@"icon-allow-overlap should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconAllowsOverlap;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconAllowsOverlap = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconAllowsOverlap = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
@"Setting iconAllowsOverlap to a constant value should update icon-allow-overlap.");
- XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue,
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, constantStyleValue,
@"iconAllowsOverlap should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconAllowsOverlap = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconAllowsOverlap = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
- @"Setting iconAllowsOverlap to a function should update icon-allow-overlap.");
- XCTAssertEqualObjects(layer.iconAllowsOverlap, styleValue,
- @"iconAllowsOverlap should round-trip functions.");
-
+ @"Setting iconAllowsOverlap to a camera function should update icon-allow-overlap.");
+ XCTAssertEqualObjects(layer.iconAllowsOverlap, functionStyleValue,
+ @"iconAllowsOverlap should round-trip camera functions.");
+
+
+
layer.iconAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@"Unsetting iconAllowsOverlap should return icon-allow-overlap to the default value.");
XCTAssertEqualObjects(layer.iconAllowsOverlap, defaultStyleValue,
@"iconAllowsOverlap should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-ignore-placement
{
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@"icon-ignore-placement should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconIgnoresPlacement;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconIgnoresPlacement = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconIgnoresPlacement = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
@"Setting iconIgnoresPlacement to a constant value should update icon-ignore-placement.");
- XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue,
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, constantStyleValue,
@"iconIgnoresPlacement should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconIgnoresPlacement = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconIgnoresPlacement = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
- @"Setting iconIgnoresPlacement to a function should update icon-ignore-placement.");
- XCTAssertEqualObjects(layer.iconIgnoresPlacement, styleValue,
- @"iconIgnoresPlacement should round-trip functions.");
-
+ @"Setting iconIgnoresPlacement to a camera function should update icon-ignore-placement.");
+ XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionStyleValue,
+ @"iconIgnoresPlacement should round-trip camera functions.");
+
+
+
layer.iconIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@"Unsetting iconIgnoresPlacement should return icon-ignore-placement to the default value.");
XCTAssertEqualObjects(layer.iconIgnoresPlacement, defaultStyleValue,
@"iconIgnoresPlacement should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-image
{
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@"icon-image should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.iconImageName;
-
- MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"];
- layer.iconImageName = styleValue;
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Icon Image"];
+ layer.iconImageName = constantStyleValue;
mbgl::style::PropertyValue<std::string> propertyValue = { "Icon Image" };
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
@"Setting iconImageName to a constant value should update icon-image.");
- XCTAssertEqualObjects(layer.iconImageName, styleValue,
+ XCTAssertEqualObjects(layer.iconImageName, constantStyleValue,
@"iconImageName should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconImageName = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Icon Image"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
- styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconImageName = styleValue;
- propertyValue = { mbgl::style::Function<std::string> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
- @"Setting iconImageName to a function should update icon-image.");
- XCTAssertEqualObjects(layer.iconImageName, styleValue,
- @"iconImageName should round-trip functions.");
-
+ @"Setting iconImageName to a camera function should update icon-image.");
+ XCTAssertEqualObjects(layer.iconImageName, functionStyleValue,
+ @"iconImageName should round-trip camera functions.");
+
+
+
layer.iconImageName = nil;
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@"Unsetting iconImageName should return icon-image to the default value.");
XCTAssertEqualObjects(layer.iconImageName, defaultStyleValue,
@"iconImageName should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconImageName = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-offset
{
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@"icon-offset should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconOffset;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.iconOffset = styleValue;
- mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
+ layer.iconOffset = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
@"Setting iconOffset to a constant value should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, styleValue,
+ XCTAssertEqualObjects(layer.iconOffset, constantStyleValue,
@"iconOffset should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconOffset = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconOffset = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
- @"Setting iconOffset to a function should update icon-offset.");
- XCTAssertEqualObjects(layer.iconOffset, styleValue,
- @"iconOffset should round-trip functions.");
-
+ @"Setting iconOffset to a camera function should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
+ @"iconOffset should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconOffset = functionStyleValue;
+
+ mbgl::style::ExponentialStops<std::array<float, 2>> exponentialStops = { {{18, { 1, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<std::array<float, 2>> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
+ @"Setting iconOffset to a source function should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
+ @"iconOffset should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconOffset = functionStyleValue;
+
+ std::map<float, std::array<float, 2>> innerStops { {18, { 1, 1 }} };
+ mbgl::style::CompositeExponentialStops<std::array<float, 2>> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<std::array<float, 2>> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
+ @"Setting iconOffset to a composite function should update icon-offset.");
+ XCTAssertEqualObjects(layer.iconOffset, functionStyleValue,
+ @"iconOffset should round-trip composite functions.");
+
+
layer.iconOffset = nil;
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@"Unsetting iconOffset should return icon-offset to the default value.");
XCTAssertEqualObjects(layer.iconOffset, defaultStyleValue,
@"iconOffset should return the default value after being unset.");
}
-
+
// icon-optional
{
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@"icon-optional should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOptional;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.iconOptional = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.iconOptional = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
@"Setting iconOptional to a constant value should update icon-optional.");
- XCTAssertEqualObjects(layer.iconOptional, styleValue,
+ XCTAssertEqualObjects(layer.iconOptional, constantStyleValue,
@"iconOptional should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconOptional = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconOptional = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
- @"Setting iconOptional to a function should update icon-optional.");
- XCTAssertEqualObjects(layer.iconOptional, styleValue,
- @"iconOptional should round-trip functions.");
-
+ @"Setting iconOptional to a camera function should update icon-optional.");
+ XCTAssertEqualObjects(layer.iconOptional, functionStyleValue,
+ @"iconOptional should round-trip camera functions.");
+
+
+
layer.iconOptional = nil;
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@"Unsetting iconOptional should return icon-optional to the default value.");
XCTAssertEqualObjects(layer.iconOptional, defaultStyleValue,
@"iconOptional should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-padding
{
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@"icon-padding should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconPadding;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconPadding = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconPadding = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
@"Setting iconPadding to a constant value should update icon-padding.");
- XCTAssertEqualObjects(layer.iconPadding, styleValue,
+ XCTAssertEqualObjects(layer.iconPadding, constantStyleValue,
@"iconPadding should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconPadding = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconPadding = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
- @"Setting iconPadding to a function should update icon-padding.");
- XCTAssertEqualObjects(layer.iconPadding, styleValue,
- @"iconPadding should round-trip functions.");
-
+ @"Setting iconPadding to a camera function should update icon-padding.");
+ XCTAssertEqualObjects(layer.iconPadding, functionStyleValue,
+ @"iconPadding should round-trip camera functions.");
+
+
+
layer.iconPadding = nil;
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@"Unsetting iconPadding should return icon-padding to the default value.");
XCTAssertEqualObjects(layer.iconPadding, defaultStyleValue,
@"iconPadding should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-rotate
{
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@"icon-rotate should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconRotation;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconRotation = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconRotation = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
@"Setting iconRotation to a constant value should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, styleValue,
+ XCTAssertEqualObjects(layer.iconRotation, constantStyleValue,
@"iconRotation should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconRotation = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconRotation = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
- @"Setting iconRotation to a function should update icon-rotate.");
- XCTAssertEqualObjects(layer.iconRotation, styleValue,
- @"iconRotation should round-trip functions.");
-
+ @"Setting iconRotation to a camera function should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
+ @"iconRotation should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconRotation = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
+ @"Setting iconRotation to a source function should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
+ @"iconRotation should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconRotation = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
+ @"Setting iconRotation to a composite function should update icon-rotate.");
+ XCTAssertEqualObjects(layer.iconRotation, functionStyleValue,
+ @"iconRotation should round-trip composite functions.");
+
+
layer.iconRotation = nil;
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@"Unsetting iconRotation should return icon-rotate to the default value.");
XCTAssertEqualObjects(layer.iconRotation, defaultStyleValue,
@"iconRotation should return the default value after being unset.");
}
-
+
// icon-rotation-alignment
{
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@"icon-rotation-alignment should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconRotationAlignment;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]];
- layer.iconRotationAlignment = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconRotationAlignment:MGLIconRotationAlignmentAuto]];
+ layer.iconRotationAlignment = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
@"Setting iconRotationAlignment to a constant value should update icon-rotation-alignment.");
- XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue,
+ XCTAssertEqualObjects(layer.iconRotationAlignment, constantStyleValue,
@"iconRotationAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconRotationAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconRotationAlignment = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
- @"Setting iconRotationAlignment to a function should update icon-rotation-alignment.");
- XCTAssertEqualObjects(layer.iconRotationAlignment, styleValue,
- @"iconRotationAlignment should round-trip functions.");
-
+ @"Setting iconRotationAlignment to a camera function should update icon-rotation-alignment.");
+ XCTAssertEqualObjects(layer.iconRotationAlignment, functionStyleValue,
+ @"iconRotationAlignment should round-trip camera functions.");
+
+
+
layer.iconRotationAlignment = nil;
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@"Unsetting iconRotationAlignment should return icon-rotation-alignment to the default value.");
XCTAssertEqualObjects(layer.iconRotationAlignment, defaultStyleValue,
@"iconRotationAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-size
{
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@"icon-size should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconScale;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconScale = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconScale = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
@"Setting iconScale to a constant value should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, styleValue,
+ XCTAssertEqualObjects(layer.iconScale, constantStyleValue,
@"iconScale should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconScale = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconScale = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
- @"Setting iconScale to a function should update icon-size.");
- XCTAssertEqualObjects(layer.iconScale, styleValue,
- @"iconScale should round-trip functions.");
-
+ @"Setting iconScale to a camera function should update icon-size.");
+ XCTAssertEqualObjects(layer.iconScale, functionStyleValue,
+ @"iconScale should round-trip camera functions.");
+
+
+
layer.iconScale = nil;
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@"Unsetting iconScale should return icon-size to the default value.");
XCTAssertEqualObjects(layer.iconScale, defaultStyleValue,
@"iconScale should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconScale = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-text-fit
{
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@"icon-text-fit should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFit;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]];
- layer.iconTextFit = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTextFit:MGLIconTextFitBoth]];
+ layer.iconTextFit = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::IconTextFitType> propertyValue = { mbgl::style::IconTextFitType::Both };
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
@"Setting iconTextFit to a constant value should update icon-text-fit.");
- XCTAssertEqualObjects(layer.iconTextFit, styleValue,
+ XCTAssertEqualObjects(layer.iconTextFit, constantStyleValue,
@"iconTextFit should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconTextFit = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::IconTextFitType> intervalStops = { {{18, mbgl::style::IconTextFitType::Both}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::IconTextFitType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconTextFit = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::IconTextFitType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
- @"Setting iconTextFit to a function should update icon-text-fit.");
- XCTAssertEqualObjects(layer.iconTextFit, styleValue,
- @"iconTextFit should round-trip functions.");
-
+ @"Setting iconTextFit to a camera function should update icon-text-fit.");
+ XCTAssertEqualObjects(layer.iconTextFit, functionStyleValue,
+ @"iconTextFit should round-trip camera functions.");
+
+
+
layer.iconTextFit = nil;
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@"Unsetting iconTextFit should return icon-text-fit to the default value.");
XCTAssertEqualObjects(layer.iconTextFit, defaultStyleValue,
@"iconTextFit should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFit = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-text-fit-padding
{
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@"icon-text-fit-padding should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTextFitPadding;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]
#else
[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]
#endif
];
- layer.iconTextFitPadding = styleValue;
+ layer.iconTextFitPadding = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 4>> propertyValue = { { 1, 1, 1, 1 } };
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
@"Setting iconTextFitPadding to a constant value should update icon-text-fit-padding.");
- XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue,
+ XCTAssertEqualObjects(layer.iconTextFitPadding, constantStyleValue,
@"iconTextFitPadding should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconTextFitPadding = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 4>> intervalStops = { {{18, { 1, 1, 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 4>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconTextFitPadding = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 4>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
- @"Setting iconTextFitPadding to a function should update icon-text-fit-padding.");
- XCTAssertEqualObjects(layer.iconTextFitPadding, styleValue,
- @"iconTextFitPadding should round-trip functions.");
-
+ @"Setting iconTextFitPadding to a camera function should update icon-text-fit-padding.");
+ XCTAssertEqualObjects(layer.iconTextFitPadding, functionStyleValue,
+ @"iconTextFitPadding should round-trip camera functions.");
+
+
+
layer.iconTextFitPadding = nil;
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@"Unsetting iconTextFitPadding should return icon-text-fit-padding to the default value.");
XCTAssertEqualObjects(layer.iconTextFitPadding, defaultStyleValue,
@"iconTextFitPadding should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTextFitPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-keep-upright
{
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@"icon-keep-upright should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsIconUpright;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.keepsIconUpright = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.keepsIconUpright = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
@"Setting keepsIconUpright to a constant value should update icon-keep-upright.");
- XCTAssertEqualObjects(layer.keepsIconUpright, styleValue,
+ XCTAssertEqualObjects(layer.keepsIconUpright, constantStyleValue,
@"keepsIconUpright should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.keepsIconUpright = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.keepsIconUpright = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
- @"Setting keepsIconUpright to a function should update icon-keep-upright.");
- XCTAssertEqualObjects(layer.keepsIconUpright, styleValue,
- @"keepsIconUpright should round-trip functions.");
-
+ @"Setting keepsIconUpright to a camera function should update icon-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsIconUpright, functionStyleValue,
+ @"keepsIconUpright should round-trip camera functions.");
+
+
+
layer.keepsIconUpright = nil;
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@"Unsetting keepsIconUpright should return icon-keep-upright to the default value.");
XCTAssertEqualObjects(layer.keepsIconUpright, defaultStyleValue,
@"keepsIconUpright should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.keepsIconUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-keep-upright
{
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@"text-keep-upright should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.keepsTextUpright;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
- layer.keepsTextUpright = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@NO];
+ layer.keepsTextUpright = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { false };
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
@"Setting keepsTextUpright to a constant value should update text-keep-upright.");
- XCTAssertEqualObjects(layer.keepsTextUpright, styleValue,
+ XCTAssertEqualObjects(layer.keepsTextUpright, constantStyleValue,
@"keepsTextUpright should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.keepsTextUpright = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, false}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.keepsTextUpright = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
- @"Setting keepsTextUpright to a function should update text-keep-upright.");
- XCTAssertEqualObjects(layer.keepsTextUpright, styleValue,
- @"keepsTextUpright should round-trip functions.");
-
+ @"Setting keepsTextUpright to a camera function should update text-keep-upright.");
+ XCTAssertEqualObjects(layer.keepsTextUpright, functionStyleValue,
+ @"keepsTextUpright should round-trip camera functions.");
+
+
+
layer.keepsTextUpright = nil;
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@"Unsetting keepsTextUpright should return text-keep-upright to the default value.");
XCTAssertEqualObjects(layer.keepsTextUpright, defaultStyleValue,
@"keepsTextUpright should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.keepsTextUpright = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-max-angle
{
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@"text-max-angle should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextAngle;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumTextAngle = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumTextAngle = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
@"Setting maximumTextAngle to a constant value should update text-max-angle.");
- XCTAssertEqualObjects(layer.maximumTextAngle, styleValue,
+ XCTAssertEqualObjects(layer.maximumTextAngle, constantStyleValue,
@"maximumTextAngle should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.maximumTextAngle = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.maximumTextAngle = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
- @"Setting maximumTextAngle to a function should update text-max-angle.");
- XCTAssertEqualObjects(layer.maximumTextAngle, styleValue,
- @"maximumTextAngle should round-trip functions.");
-
+ @"Setting maximumTextAngle to a camera function should update text-max-angle.");
+ XCTAssertEqualObjects(layer.maximumTextAngle, functionStyleValue,
+ @"maximumTextAngle should round-trip camera functions.");
+
+
+
layer.maximumTextAngle = nil;
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@"Unsetting maximumTextAngle should return text-max-angle to the default value.");
XCTAssertEqualObjects(layer.maximumTextAngle, defaultStyleValue,
@"maximumTextAngle should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextAngle = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-max-width
{
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@"text-max-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.maximumTextWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.maximumTextWidth = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.maximumTextWidth = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
@"Setting maximumTextWidth to a constant value should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, styleValue,
+ XCTAssertEqualObjects(layer.maximumTextWidth, constantStyleValue,
@"maximumTextWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.maximumTextWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.maximumTextWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
- @"Setting maximumTextWidth to a function should update text-max-width.");
- XCTAssertEqualObjects(layer.maximumTextWidth, styleValue,
- @"maximumTextWidth should round-trip functions.");
-
+ @"Setting maximumTextWidth to a camera function should update text-max-width.");
+ XCTAssertEqualObjects(layer.maximumTextWidth, functionStyleValue,
+ @"maximumTextWidth should round-trip camera functions.");
+
+
+
layer.maximumTextWidth = nil;
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@"Unsetting maximumTextWidth should return text-max-width to the default value.");
XCTAssertEqualObjects(layer.maximumTextWidth, defaultStyleValue,
@"maximumTextWidth should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.maximumTextWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// symbol-avoid-edges
{
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@"symbol-avoid-edges should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolAvoidsEdges;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.symbolAvoidsEdges = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.symbolAvoidsEdges = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
@"Setting symbolAvoidsEdges to a constant value should update symbol-avoid-edges.");
- XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue,
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, constantStyleValue,
@"symbolAvoidsEdges should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.symbolAvoidsEdges = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.symbolAvoidsEdges = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
- @"Setting symbolAvoidsEdges to a function should update symbol-avoid-edges.");
- XCTAssertEqualObjects(layer.symbolAvoidsEdges, styleValue,
- @"symbolAvoidsEdges should round-trip functions.");
-
+ @"Setting symbolAvoidsEdges to a camera function should update symbol-avoid-edges.");
+ XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionStyleValue,
+ @"symbolAvoidsEdges should round-trip camera functions.");
+
+
+
layer.symbolAvoidsEdges = nil;
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@"Unsetting symbolAvoidsEdges should return symbol-avoid-edges to the default value.");
XCTAssertEqualObjects(layer.symbolAvoidsEdges, defaultStyleValue,
@"symbolAvoidsEdges should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolAvoidsEdges = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// symbol-placement
{
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@"symbol-placement should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.symbolPlacement;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]];
- layer.symbolPlacement = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLSymbolPlacement:MGLSymbolPlacementLine]];
+ layer.symbolPlacement = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::SymbolPlacementType> propertyValue = { mbgl::style::SymbolPlacementType::Line };
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
@"Setting symbolPlacement to a constant value should update symbol-placement.");
- XCTAssertEqualObjects(layer.symbolPlacement, styleValue,
+ XCTAssertEqualObjects(layer.symbolPlacement, constantStyleValue,
@"symbolPlacement should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.symbolPlacement = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::SymbolPlacementType> intervalStops = { {{18, mbgl::style::SymbolPlacementType::Line}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolPlacementType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.symbolPlacement = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::SymbolPlacementType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
- @"Setting symbolPlacement to a function should update symbol-placement.");
- XCTAssertEqualObjects(layer.symbolPlacement, styleValue,
- @"symbolPlacement should round-trip functions.");
-
+ @"Setting symbolPlacement to a camera function should update symbol-placement.");
+ XCTAssertEqualObjects(layer.symbolPlacement, functionStyleValue,
+ @"symbolPlacement should round-trip camera functions.");
+
+
+
layer.symbolPlacement = nil;
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@"Unsetting symbolPlacement should return symbol-placement to the default value.");
XCTAssertEqualObjects(layer.symbolPlacement, defaultStyleValue,
@"symbolPlacement should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// symbol-spacing
{
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@"symbol-spacing should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.symbolSpacing;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.symbolSpacing = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.symbolSpacing = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
@"Setting symbolSpacing to a constant value should update symbol-spacing.");
- XCTAssertEqualObjects(layer.symbolSpacing, styleValue,
+ XCTAssertEqualObjects(layer.symbolSpacing, constantStyleValue,
@"symbolSpacing should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.symbolSpacing = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.symbolSpacing = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
- @"Setting symbolSpacing to a function should update symbol-spacing.");
- XCTAssertEqualObjects(layer.symbolSpacing, styleValue,
- @"symbolSpacing should round-trip functions.");
-
+ @"Setting symbolSpacing to a camera function should update symbol-spacing.");
+ XCTAssertEqualObjects(layer.symbolSpacing, functionStyleValue,
+ @"symbolSpacing should round-trip camera functions.");
+
+
+
layer.symbolSpacing = nil;
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@"Unsetting symbolSpacing should return symbol-spacing to the default value.");
XCTAssertEqualObjects(layer.symbolSpacing, defaultStyleValue,
@"symbolSpacing should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.symbolSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-field
{
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@"text-field should be unset initially.");
MGLStyleValue<NSString *> *defaultStyleValue = layer.text;
-
- MGLStyleValue<NSString *> *styleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Text Field"];
- layer.text = styleValue;
- mbgl::style::PropertyValue<std::string> propertyValue = { "Text Field" };
+
+ MGLStyleValue<NSString *> *constantStyleValue = [MGLStyleValue<NSString *> valueWithRawValue:@"Text Field"];
+ layer.text = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<std::string> propertyValue = { "Text Field" };
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
@"Setting text to a constant value should update text-field.");
- XCTAssertEqualObjects(layer.text, styleValue,
+ XCTAssertEqualObjects(layer.text, constantStyleValue,
@"text should round-trip constant values.");
+
+ MGLStyleValue<NSString *> * functionStyleValue = [MGLStyleValue<NSString *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.text = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::string> intervalStops = { {{18, "Text Field"}} };
+ propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
- styleValue = [MGLStyleValue<NSString *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.text = styleValue;
- propertyValue = { mbgl::style::Function<std::string> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
- @"Setting text to a function should update text-field.");
- XCTAssertEqualObjects(layer.text, styleValue,
- @"text should round-trip functions.");
-
+ @"Setting text to a camera function should update text-field.");
+ XCTAssertEqualObjects(layer.text, functionStyleValue,
+ @"text should round-trip camera functions.");
+
+
+
layer.text = nil;
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@"Unsetting text should return text-field to the default value.");
XCTAssertEqualObjects(layer.text, defaultStyleValue,
@"text should return the default value after being unset.");
}
-
+
// text-allow-overlap
{
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@"text-allow-overlap should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textAllowsOverlap;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textAllowsOverlap = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textAllowsOverlap = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
@"Setting textAllowsOverlap to a constant value should update text-allow-overlap.");
- XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue,
+ XCTAssertEqualObjects(layer.textAllowsOverlap, constantStyleValue,
@"textAllowsOverlap should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textAllowsOverlap = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textAllowsOverlap = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
- @"Setting textAllowsOverlap to a function should update text-allow-overlap.");
- XCTAssertEqualObjects(layer.textAllowsOverlap, styleValue,
- @"textAllowsOverlap should round-trip functions.");
-
+ @"Setting textAllowsOverlap to a camera function should update text-allow-overlap.");
+ XCTAssertEqualObjects(layer.textAllowsOverlap, functionStyleValue,
+ @"textAllowsOverlap should round-trip camera functions.");
+
+
+
layer.textAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@"Unsetting textAllowsOverlap should return text-allow-overlap to the default value.");
XCTAssertEqualObjects(layer.textAllowsOverlap, defaultStyleValue,
@"textAllowsOverlap should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textAllowsOverlap = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-anchor
{
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@"text-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
- layer.textAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight]];
+ layer.textAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TextAnchorType> propertyValue = { mbgl::style::TextAnchorType::BottomRight };
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
@"Setting textAnchor to a constant value should update text-anchor.");
- XCTAssertEqualObjects(layer.textAnchor, styleValue,
+ XCTAssertEqualObjects(layer.textAnchor, constantStyleValue,
@"textAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TextAnchorType> intervalStops = { {{18, mbgl::style::TextAnchorType::BottomRight}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TextAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TextAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
- @"Setting textAnchor to a function should update text-anchor.");
- XCTAssertEqualObjects(layer.textAnchor, styleValue,
- @"textAnchor should round-trip functions.");
-
+ @"Setting textAnchor to a camera function should update text-anchor.");
+ XCTAssertEqualObjects(layer.textAnchor, functionStyleValue,
+ @"textAnchor should round-trip camera functions.");
+
+
+
layer.textAnchor = nil;
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@"Unsetting textAnchor should return text-anchor to the default value.");
XCTAssertEqualObjects(layer.textAnchor, defaultStyleValue,
@"textAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-font
{
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@"text-font should be unset initially.");
MGLStyleValue<NSArray<NSString *> *> *defaultStyleValue = layer.textFontNames;
-
- MGLStyleValue<NSArray<NSString *> *> *styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]];
- layer.textFontNames = styleValue;
+
+ MGLStyleValue<NSArray<NSString *> *> *constantStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithRawValue:@[@"Text Font", @"Tnof Txet"]];
+ layer.textFontNames = constantStyleValue;
mbgl::style::PropertyValue<std::vector<std::string>> propertyValue = { { "Text Font", "Tnof Txet" } };
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
@"Setting textFontNames to a constant value should update text-font.");
- XCTAssertEqualObjects(layer.textFontNames, styleValue,
+ XCTAssertEqualObjects(layer.textFontNames, constantStyleValue,
@"textFontNames should round-trip constant values.");
+
+ MGLStyleValue<NSArray<NSString *> *> * functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textFontNames = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::vector<std::string>> intervalStops = { {{18, { "Text Font", "Tnof Txet" }}} };
+ propertyValue = mbgl::style::CameraFunction<std::vector<std::string>> { intervalStops };
- styleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textFontNames = styleValue;
- propertyValue = { mbgl::style::Function<std::vector<std::string>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
- @"Setting textFontNames to a function should update text-font.");
- XCTAssertEqualObjects(layer.textFontNames, styleValue,
- @"textFontNames should round-trip functions.");
-
+ @"Setting textFontNames to a camera function should update text-font.");
+ XCTAssertEqualObjects(layer.textFontNames, functionStyleValue,
+ @"textFontNames should round-trip camera functions.");
+
+
+
layer.textFontNames = nil;
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@"Unsetting textFontNames should return text-font to the default value.");
XCTAssertEqualObjects(layer.textFontNames, defaultStyleValue,
@"textFontNames should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textFontNames = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSArray<NSString *> *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textFontNames = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-size
{
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@"text-size should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textFontSize;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textFontSize = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textFontSize = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
@"Setting textFontSize to a constant value should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, styleValue,
+ XCTAssertEqualObjects(layer.textFontSize, constantStyleValue,
@"textFontSize should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textFontSize = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textFontSize = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
- @"Setting textFontSize to a function should update text-size.");
- XCTAssertEqualObjects(layer.textFontSize, styleValue,
- @"textFontSize should round-trip functions.");
-
+ @"Setting textFontSize to a camera function should update text-size.");
+ XCTAssertEqualObjects(layer.textFontSize, functionStyleValue,
+ @"textFontSize should round-trip camera functions.");
+
+
+
layer.textFontSize = nil;
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@"Unsetting textFontSize should return text-size to the default value.");
XCTAssertEqualObjects(layer.textFontSize, defaultStyleValue,
@"textFontSize should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textFontSize = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-ignore-placement
{
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@"text-ignore-placement should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textIgnoresPlacement;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textIgnoresPlacement = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textIgnoresPlacement = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
@"Setting textIgnoresPlacement to a constant value should update text-ignore-placement.");
- XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue,
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, constantStyleValue,
@"textIgnoresPlacement should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textIgnoresPlacement = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textIgnoresPlacement = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
- @"Setting textIgnoresPlacement to a function should update text-ignore-placement.");
- XCTAssertEqualObjects(layer.textIgnoresPlacement, styleValue,
- @"textIgnoresPlacement should round-trip functions.");
-
+ @"Setting textIgnoresPlacement to a camera function should update text-ignore-placement.");
+ XCTAssertEqualObjects(layer.textIgnoresPlacement, functionStyleValue,
+ @"textIgnoresPlacement should round-trip camera functions.");
+
+
+
layer.textIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@"Unsetting textIgnoresPlacement should return text-ignore-placement to the default value.");
XCTAssertEqualObjects(layer.textIgnoresPlacement, defaultStyleValue,
@"textIgnoresPlacement should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textIgnoresPlacement = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-justify
{
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@"text-justify should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textJustification;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]];
- layer.textJustification = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextJustification:MGLTextJustificationRight]];
+ layer.textJustification = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TextJustifyType> propertyValue = { mbgl::style::TextJustifyType::Right };
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
@"Setting textJustification to a constant value should update text-justify.");
- XCTAssertEqualObjects(layer.textJustification, styleValue,
+ XCTAssertEqualObjects(layer.textJustification, constantStyleValue,
@"textJustification should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textJustification = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TextJustifyType> intervalStops = { {{18, mbgl::style::TextJustifyType::Right}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TextJustifyType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textJustification = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TextJustifyType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
- @"Setting textJustification to a function should update text-justify.");
- XCTAssertEqualObjects(layer.textJustification, styleValue,
- @"textJustification should round-trip functions.");
-
+ @"Setting textJustification to a camera function should update text-justify.");
+ XCTAssertEqualObjects(layer.textJustification, functionStyleValue,
+ @"textJustification should round-trip camera functions.");
+
+
+
layer.textJustification = nil;
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@"Unsetting textJustification should return text-justify to the default value.");
XCTAssertEqualObjects(layer.textJustification, defaultStyleValue,
@"textJustification should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textJustification = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-letter-spacing
{
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@"text-letter-spacing should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLetterSpacing;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textLetterSpacing = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textLetterSpacing = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
@"Setting textLetterSpacing to a constant value should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, styleValue,
+ XCTAssertEqualObjects(layer.textLetterSpacing, constantStyleValue,
@"textLetterSpacing should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textLetterSpacing = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textLetterSpacing = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
- @"Setting textLetterSpacing to a function should update text-letter-spacing.");
- XCTAssertEqualObjects(layer.textLetterSpacing, styleValue,
- @"textLetterSpacing should round-trip functions.");
-
+ @"Setting textLetterSpacing to a camera function should update text-letter-spacing.");
+ XCTAssertEqualObjects(layer.textLetterSpacing, functionStyleValue,
+ @"textLetterSpacing should round-trip camera functions.");
+
+
+
layer.textLetterSpacing = nil;
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@"Unsetting textLetterSpacing should return text-letter-spacing to the default value.");
XCTAssertEqualObjects(layer.textLetterSpacing, defaultStyleValue,
@"textLetterSpacing should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textLetterSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textLetterSpacing = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-line-height
{
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@"text-line-height should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textLineHeight;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textLineHeight = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textLineHeight = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
@"Setting textLineHeight to a constant value should update text-line-height.");
- XCTAssertEqualObjects(layer.textLineHeight, styleValue,
+ XCTAssertEqualObjects(layer.textLineHeight, constantStyleValue,
@"textLineHeight should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textLineHeight = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textLineHeight = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
- @"Setting textLineHeight to a function should update text-line-height.");
- XCTAssertEqualObjects(layer.textLineHeight, styleValue,
- @"textLineHeight should round-trip functions.");
-
+ @"Setting textLineHeight to a camera function should update text-line-height.");
+ XCTAssertEqualObjects(layer.textLineHeight, functionStyleValue,
+ @"textLineHeight should round-trip camera functions.");
+
+
+
layer.textLineHeight = nil;
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@"Unsetting textLineHeight should return text-line-height to the default value.");
XCTAssertEqualObjects(layer.textLineHeight, defaultStyleValue,
@"textLineHeight should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textLineHeight = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-offset
{
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@"text-offset should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textOffset;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.textOffset = styleValue;
+ layer.textOffset = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
@"Setting textOffset to a constant value should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, styleValue,
+ XCTAssertEqualObjects(layer.textOffset, constantStyleValue,
@"textOffset should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textOffset = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textOffset = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
- @"Setting textOffset to a function should update text-offset.");
- XCTAssertEqualObjects(layer.textOffset, styleValue,
- @"textOffset should round-trip functions.");
-
+ @"Setting textOffset to a camera function should update text-offset.");
+ XCTAssertEqualObjects(layer.textOffset, functionStyleValue,
+ @"textOffset should round-trip camera functions.");
+
+
+
layer.textOffset = nil;
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@"Unsetting textOffset should return text-offset to the default value.");
XCTAssertEqualObjects(layer.textOffset, defaultStyleValue,
@"textOffset should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textOffset = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textOffset = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-optional
{
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@"text-optional should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOptional;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
- layer.textOptional = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@YES];
+ layer.textOptional = constantStyleValue;
mbgl::style::PropertyValue<bool> propertyValue = { true };
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
@"Setting textOptional to a constant value should update text-optional.");
- XCTAssertEqualObjects(layer.textOptional, styleValue,
+ XCTAssertEqualObjects(layer.textOptional, constantStyleValue,
@"textOptional should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textOptional = functionStyleValue;
+
+ mbgl::style::IntervalStops<bool> intervalStops = { {{18, true}} };
+ propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textOptional = styleValue;
- propertyValue = { mbgl::style::Function<bool> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
- @"Setting textOptional to a function should update text-optional.");
- XCTAssertEqualObjects(layer.textOptional, styleValue,
- @"textOptional should round-trip functions.");
-
+ @"Setting textOptional to a camera function should update text-optional.");
+ XCTAssertEqualObjects(layer.textOptional, functionStyleValue,
+ @"textOptional should round-trip camera functions.");
+
+
+
layer.textOptional = nil;
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@"Unsetting textOptional should return text-optional to the default value.");
XCTAssertEqualObjects(layer.textOptional, defaultStyleValue,
@"textOptional should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textOptional = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-padding
{
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@"text-padding should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textPadding;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textPadding = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textPadding = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
@"Setting textPadding to a constant value should update text-padding.");
- XCTAssertEqualObjects(layer.textPadding, styleValue,
+ XCTAssertEqualObjects(layer.textPadding, constantStyleValue,
@"textPadding should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textPadding = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textPadding = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
- @"Setting textPadding to a function should update text-padding.");
- XCTAssertEqualObjects(layer.textPadding, styleValue,
- @"textPadding should round-trip functions.");
-
+ @"Setting textPadding to a camera function should update text-padding.");
+ XCTAssertEqualObjects(layer.textPadding, functionStyleValue,
+ @"textPadding should round-trip camera functions.");
+
+
+
layer.textPadding = nil;
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@"Unsetting textPadding should return text-padding to the default value.");
XCTAssertEqualObjects(layer.textPadding, defaultStyleValue,
@"textPadding should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textPadding = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-pitch-alignment
{
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@"text-pitch-alignment should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textPitchAlignment;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]];
- layer.textPitchAlignment = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextPitchAlignment:MGLTextPitchAlignmentAuto]];
+ layer.textPitchAlignment = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
@"Setting textPitchAlignment to a constant value should update text-pitch-alignment.");
- XCTAssertEqualObjects(layer.textPitchAlignment, styleValue,
+ XCTAssertEqualObjects(layer.textPitchAlignment, constantStyleValue,
@"textPitchAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textPitchAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textPitchAlignment = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
- @"Setting textPitchAlignment to a function should update text-pitch-alignment.");
- XCTAssertEqualObjects(layer.textPitchAlignment, styleValue,
- @"textPitchAlignment should round-trip functions.");
-
+ @"Setting textPitchAlignment to a camera function should update text-pitch-alignment.");
+ XCTAssertEqualObjects(layer.textPitchAlignment, functionStyleValue,
+ @"textPitchAlignment should round-trip camera functions.");
+
+
+
layer.textPitchAlignment = nil;
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@"Unsetting textPitchAlignment should return text-pitch-alignment to the default value.");
XCTAssertEqualObjects(layer.textPitchAlignment, defaultStyleValue,
@"textPitchAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-rotate
{
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@"text-rotate should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textRotation;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textRotation = styleValue;
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textRotation = constantStyleValue;
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
@"Setting textRotation to a constant value should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, styleValue,
+ XCTAssertEqualObjects(layer.textRotation, constantStyleValue,
@"textRotation should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textRotation = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textRotation = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
- @"Setting textRotation to a function should update text-rotate.");
- XCTAssertEqualObjects(layer.textRotation, styleValue,
- @"textRotation should round-trip functions.");
-
+ @"Setting textRotation to a camera function should update text-rotate.");
+ XCTAssertEqualObjects(layer.textRotation, functionStyleValue,
+ @"textRotation should round-trip camera functions.");
+
+
+
layer.textRotation = nil;
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@"Unsetting textRotation should return text-rotate to the default value.");
XCTAssertEqualObjects(layer.textRotation, defaultStyleValue,
@"textRotation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textRotation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-rotation-alignment
{
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@"text-rotation-alignment should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textRotationAlignment;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]];
- layer.textRotationAlignment = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextRotationAlignment:MGLTextRotationAlignmentAuto]];
+ layer.textRotationAlignment = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::AlignmentType> propertyValue = { mbgl::style::AlignmentType::Auto };
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
@"Setting textRotationAlignment to a constant value should update text-rotation-alignment.");
- XCTAssertEqualObjects(layer.textRotationAlignment, styleValue,
+ XCTAssertEqualObjects(layer.textRotationAlignment, constantStyleValue,
@"textRotationAlignment should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textRotationAlignment = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::AlignmentType> intervalStops = { {{18, mbgl::style::AlignmentType::Auto}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textRotationAlignment = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::AlignmentType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
- @"Setting textRotationAlignment to a function should update text-rotation-alignment.");
- XCTAssertEqualObjects(layer.textRotationAlignment, styleValue,
- @"textRotationAlignment should round-trip functions.");
-
+ @"Setting textRotationAlignment to a camera function should update text-rotation-alignment.");
+ XCTAssertEqualObjects(layer.textRotationAlignment, functionStyleValue,
+ @"textRotationAlignment should round-trip camera functions.");
+
+
+
layer.textRotationAlignment = nil;
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@"Unsetting textRotationAlignment should return text-rotation-alignment to the default value.");
XCTAssertEqualObjects(layer.textRotationAlignment, defaultStyleValue,
@"textRotationAlignment should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textRotationAlignment = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-transform
{
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@"text-transform should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTransform;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]];
- layer.textTransform = styleValue;
- mbgl::style::PropertyValue<mbgl::style::TextTransformType> propertyValue = { mbgl::style::TextTransformType::Lowercase };
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTransform:MGLTextTransformLowercase]];
+ layer.textTransform = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::style::TextTransformType> propertyValue = { mbgl::style::TextTransformType::Lowercase };
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
@"Setting textTransform to a constant value should update text-transform.");
- XCTAssertEqualObjects(layer.textTransform, styleValue,
+ XCTAssertEqualObjects(layer.textTransform, constantStyleValue,
@"textTransform should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textTransform = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TextTransformType> intervalStops = { {{18, mbgl::style::TextTransformType::Lowercase}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TextTransformType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textTransform = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TextTransformType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
- @"Setting textTransform to a function should update text-transform.");
- XCTAssertEqualObjects(layer.textTransform, styleValue,
- @"textTransform should round-trip functions.");
-
+ @"Setting textTransform to a camera function should update text-transform.");
+ XCTAssertEqualObjects(layer.textTransform, functionStyleValue,
+ @"textTransform should round-trip camera functions.");
+
+
+
layer.textTransform = nil;
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@"Unsetting textTransform should return text-transform to the default value.");
XCTAssertEqualObjects(layer.textTransform, defaultStyleValue,
@"textTransform should return the default value after being unset.");
}
-
+
// icon-color
{
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@"icon-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.iconColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.iconColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a constant value should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, styleValue,
+ XCTAssertEqualObjects(layer.iconColor, constantStyleValue,
@"iconColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
- @"Setting iconColor to a function should update icon-color.");
- XCTAssertEqualObjects(layer.iconColor, styleValue,
- @"iconColor should round-trip functions.");
-
+ @"Setting iconColor to a camera function should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
+ @"iconColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
+ @"Setting iconColor to a source function should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
+ @"iconColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
+ @"Setting iconColor to a composite function should update icon-color.");
+ XCTAssertEqualObjects(layer.iconColor, functionStyleValue,
+ @"iconColor should round-trip composite functions.");
+
+
layer.iconColor = nil;
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@"Unsetting iconColor should return icon-color to the default value.");
XCTAssertEqualObjects(layer.iconColor, defaultStyleValue,
@"iconColor should return the default value after being unset.");
}
-
+
// icon-halo-blur
{
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@"icon-halo-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloBlur;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconHaloBlur = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconHaloBlur = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a constant value should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, styleValue,
+ XCTAssertEqualObjects(layer.iconHaloBlur, constantStyleValue,
@"iconHaloBlur should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconHaloBlur = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconHaloBlur = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
- @"Setting iconHaloBlur to a function should update icon-halo-blur.");
- XCTAssertEqualObjects(layer.iconHaloBlur, styleValue,
- @"iconHaloBlur should round-trip functions.");
-
+ @"Setting iconHaloBlur to a camera function should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
+ @"iconHaloBlur should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconHaloBlur = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
+ @"Setting iconHaloBlur to a source function should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
+ @"iconHaloBlur should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconHaloBlur = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
+ @"Setting iconHaloBlur to a composite function should update icon-halo-blur.");
+ XCTAssertEqualObjects(layer.iconHaloBlur, functionStyleValue,
+ @"iconHaloBlur should round-trip composite functions.");
+
+
layer.iconHaloBlur = nil;
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@"Unsetting iconHaloBlur should return icon-halo-blur to the default value.");
XCTAssertEqualObjects(layer.iconHaloBlur, defaultStyleValue,
@"iconHaloBlur should return the default value after being unset.");
}
-
+
// icon-halo-color
{
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@"icon-halo-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.iconHaloColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.iconHaloColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.iconHaloColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a constant value should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, styleValue,
+ XCTAssertEqualObjects(layer.iconHaloColor, constantStyleValue,
@"iconHaloColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconHaloColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconHaloColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
- @"Setting iconHaloColor to a function should update icon-halo-color.");
- XCTAssertEqualObjects(layer.iconHaloColor, styleValue,
- @"iconHaloColor should round-trip functions.");
-
+ @"Setting iconHaloColor to a camera function should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
+ @"iconHaloColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconHaloColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
+ @"Setting iconHaloColor to a source function should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
+ @"iconHaloColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconHaloColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
+ @"Setting iconHaloColor to a composite function should update icon-halo-color.");
+ XCTAssertEqualObjects(layer.iconHaloColor, functionStyleValue,
+ @"iconHaloColor should round-trip composite functions.");
+
+
layer.iconHaloColor = nil;
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@"Unsetting iconHaloColor should return icon-halo-color to the default value.");
XCTAssertEqualObjects(layer.iconHaloColor, defaultStyleValue,
@"iconHaloColor should return the default value after being unset.");
}
-
+
// icon-halo-width
{
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@"icon-halo-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconHaloWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconHaloWidth = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconHaloWidth = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a constant value should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, styleValue,
+ XCTAssertEqualObjects(layer.iconHaloWidth, constantStyleValue,
@"iconHaloWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconHaloWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconHaloWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
- @"Setting iconHaloWidth to a function should update icon-halo-width.");
- XCTAssertEqualObjects(layer.iconHaloWidth, styleValue,
- @"iconHaloWidth should round-trip functions.");
-
+ @"Setting iconHaloWidth to a camera function should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
+ @"iconHaloWidth should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconHaloWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
+ @"Setting iconHaloWidth to a source function should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
+ @"iconHaloWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconHaloWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
+ @"Setting iconHaloWidth to a composite function should update icon-halo-width.");
+ XCTAssertEqualObjects(layer.iconHaloWidth, functionStyleValue,
+ @"iconHaloWidth should round-trip composite functions.");
+
+
layer.iconHaloWidth = nil;
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@"Unsetting iconHaloWidth should return icon-halo-width to the default value.");
XCTAssertEqualObjects(layer.iconHaloWidth, defaultStyleValue,
@"iconHaloWidth should return the default value after being unset.");
}
-
+
// icon-opacity
{
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@"icon-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.iconOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.iconOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.iconOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a constant value should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, styleValue,
+ XCTAssertEqualObjects(layer.iconOpacity, constantStyleValue,
@"iconOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
- @"Setting iconOpacity to a function should update icon-opacity.");
- XCTAssertEqualObjects(layer.iconOpacity, styleValue,
- @"iconOpacity should round-trip functions.");
-
+ @"Setting iconOpacity to a camera function should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
+ @"iconOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.iconOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
+ @"Setting iconOpacity to a source function should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
+ @"iconOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.iconOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
+ @"Setting iconOpacity to a composite function should update icon-opacity.");
+ XCTAssertEqualObjects(layer.iconOpacity, functionStyleValue,
+ @"iconOpacity should round-trip composite functions.");
+
+
layer.iconOpacity = nil;
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@"Unsetting iconOpacity should return icon-opacity to the default value.");
XCTAssertEqualObjects(layer.iconOpacity, defaultStyleValue,
@"iconOpacity should return the default value after being unset.");
}
-
+
// icon-translate
{
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@"icon-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslation;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.iconTranslation = styleValue;
+ layer.iconTranslation = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
@"Setting iconTranslation to a constant value should update icon-translate.");
- XCTAssertEqualObjects(layer.iconTranslation, styleValue,
+ XCTAssertEqualObjects(layer.iconTranslation, constantStyleValue,
@"iconTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconTranslation = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
- @"Setting iconTranslation to a function should update icon-translate.");
- XCTAssertEqualObjects(layer.iconTranslation, styleValue,
- @"iconTranslation should round-trip functions.");
-
+ @"Setting iconTranslation to a camera function should update icon-translate.");
+ XCTAssertEqualObjects(layer.iconTranslation, functionStyleValue,
+ @"iconTranslation should round-trip camera functions.");
+
+
+
layer.iconTranslation = nil;
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@"Unsetting iconTranslation should return icon-translate to the default value.");
XCTAssertEqualObjects(layer.iconTranslation, defaultStyleValue,
@"iconTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// icon-translate-anchor
{
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@"icon-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.iconTranslationAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]];
- layer.iconTranslationAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLIconTranslationAnchor:MGLIconTranslationAnchorViewport]];
+ layer.iconTranslationAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
@"Setting iconTranslationAnchor to a constant value should update icon-translate-anchor.");
- XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue,
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, constantStyleValue,
@"iconTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.iconTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.iconTranslationAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
- @"Setting iconTranslationAnchor to a function should update icon-translate-anchor.");
- XCTAssertEqualObjects(layer.iconTranslationAnchor, styleValue,
- @"iconTranslationAnchor should round-trip functions.");
-
+ @"Setting iconTranslationAnchor to a camera function should update icon-translate-anchor.");
+ XCTAssertEqualObjects(layer.iconTranslationAnchor, functionStyleValue,
+ @"iconTranslationAnchor should round-trip camera functions.");
+
+
+
layer.iconTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@"Unsetting iconTranslationAnchor should return icon-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.iconTranslationAnchor, defaultStyleValue,
@"iconTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.iconTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-color
{
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@"text-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.textColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.textColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a constant value should update text-color.");
- XCTAssertEqualObjects(layer.textColor, styleValue,
+ XCTAssertEqualObjects(layer.textColor, constantStyleValue,
@"textColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
- @"Setting textColor to a function should update text-color.");
- XCTAssertEqualObjects(layer.textColor, styleValue,
- @"textColor should round-trip functions.");
-
+ @"Setting textColor to a camera function should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, functionStyleValue,
+ @"textColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
+ @"Setting textColor to a source function should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, functionStyleValue,
+ @"textColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
+ @"Setting textColor to a composite function should update text-color.");
+ XCTAssertEqualObjects(layer.textColor, functionStyleValue,
+ @"textColor should round-trip composite functions.");
+
+
layer.textColor = nil;
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@"Unsetting textColor should return text-color to the default value.");
XCTAssertEqualObjects(layer.textColor, defaultStyleValue,
@"textColor should return the default value after being unset.");
}
-
+
// text-halo-blur
{
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@"text-halo-blur should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloBlur;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textHaloBlur = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textHaloBlur = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a constant value should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, styleValue,
+ XCTAssertEqualObjects(layer.textHaloBlur, constantStyleValue,
@"textHaloBlur should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textHaloBlur = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textHaloBlur = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
- @"Setting textHaloBlur to a function should update text-halo-blur.");
- XCTAssertEqualObjects(layer.textHaloBlur, styleValue,
- @"textHaloBlur should round-trip functions.");
-
+ @"Setting textHaloBlur to a camera function should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
+ @"textHaloBlur should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textHaloBlur = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
+ @"Setting textHaloBlur to a source function should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
+ @"textHaloBlur should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textHaloBlur = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
+ @"Setting textHaloBlur to a composite function should update text-halo-blur.");
+ XCTAssertEqualObjects(layer.textHaloBlur, functionStyleValue,
+ @"textHaloBlur should round-trip composite functions.");
+
+
layer.textHaloBlur = nil;
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@"Unsetting textHaloBlur should return text-halo-blur to the default value.");
XCTAssertEqualObjects(layer.textHaloBlur, defaultStyleValue,
@"textHaloBlur should return the default value after being unset.");
}
-
+
// text-halo-color
{
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@"text-halo-color should be unset initially.");
MGLStyleValue<MGLColor *> *defaultStyleValue = layer.textHaloColor;
-
- MGLStyleValue<MGLColor *> *styleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
- layer.textHaloColor = styleValue;
- mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
+
+ MGLStyleValue<MGLColor *> *constantStyleValue = [MGLStyleValue<MGLColor *> valueWithRawValue:[MGLColor redColor]];
+ layer.textHaloColor = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a constant value should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, styleValue,
+ XCTAssertEqualObjects(layer.textHaloColor, constantStyleValue,
@"textHaloColor should round-trip constant values.");
+
+ MGLStyleValue<MGLColor *> * functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textHaloColor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::Color> intervalStops = { {{18, { 1, 0, 0, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
- styleValue = [MGLStyleValue<MGLColor *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textHaloColor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::Color> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
- @"Setting textHaloColor to a function should update text-halo-color.");
- XCTAssertEqualObjects(layer.textHaloColor, styleValue,
- @"textHaloColor should round-trip functions.");
-
+ @"Setting textHaloColor to a camera function should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
+ @"textHaloColor should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textHaloColor = functionStyleValue;
+
+ mbgl::style::ExponentialStops<mbgl::Color> exponentialStops = { {{18, { 1, 0, 0, 1 }}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<mbgl::Color> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
+ @"Setting textHaloColor to a source function should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
+ @"textHaloColor should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<MGLColor *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textHaloColor = functionStyleValue;
+
+ std::map<float, mbgl::Color> innerStops { {18, { 1, 0, 0, 1 }} };
+ mbgl::style::CompositeExponentialStops<mbgl::Color> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<mbgl::Color> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
+ @"Setting textHaloColor to a composite function should update text-halo-color.");
+ XCTAssertEqualObjects(layer.textHaloColor, functionStyleValue,
+ @"textHaloColor should round-trip composite functions.");
+
+
layer.textHaloColor = nil;
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@"Unsetting textHaloColor should return text-halo-color to the default value.");
XCTAssertEqualObjects(layer.textHaloColor, defaultStyleValue,
@"textHaloColor should return the default value after being unset.");
}
-
+
// text-halo-width
{
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@"text-halo-width should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textHaloWidth;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textHaloWidth = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textHaloWidth = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a constant value should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, styleValue,
+ XCTAssertEqualObjects(layer.textHaloWidth, constantStyleValue,
@"textHaloWidth should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textHaloWidth = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textHaloWidth = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
- @"Setting textHaloWidth to a function should update text-halo-width.");
- XCTAssertEqualObjects(layer.textHaloWidth, styleValue,
- @"textHaloWidth should round-trip functions.");
-
+ @"Setting textHaloWidth to a camera function should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
+ @"textHaloWidth should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textHaloWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
+ @"Setting textHaloWidth to a source function should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
+ @"textHaloWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textHaloWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
+ @"Setting textHaloWidth to a composite function should update text-halo-width.");
+ XCTAssertEqualObjects(layer.textHaloWidth, functionStyleValue,
+ @"textHaloWidth should round-trip composite functions.");
+
+
layer.textHaloWidth = nil;
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@"Unsetting textHaloWidth should return text-halo-width to the default value.");
XCTAssertEqualObjects(layer.textHaloWidth, defaultStyleValue,
@"textHaloWidth should return the default value after being unset.");
}
-
+
// text-opacity
{
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@"text-opacity should be unset initially.");
MGLStyleValue<NSNumber *> *defaultStyleValue = layer.textOpacity;
-
- MGLStyleValue<NSNumber *> *styleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
- layer.textOpacity = styleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+
+ MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
+ layer.textOpacity = constantStyleValue;
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
@"Setting textOpacity to a constant value should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, styleValue,
+ XCTAssertEqualObjects(layer.textOpacity, constantStyleValue,
@"textOpacity should round-trip constant values.");
+
+ MGLStyleValue<NSNumber *> * functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textOpacity = functionStyleValue;
+
+ mbgl::style::IntervalStops<float> intervalStops = { {{18, 0xff}} };
+ propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
- styleValue = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textOpacity = styleValue;
- propertyValue = { mbgl::style::Function<float> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
- @"Setting textOpacity to a function should update text-opacity.");
- XCTAssertEqualObjects(layer.textOpacity, styleValue,
- @"textOpacity should round-trip functions.");
-
+ @"Setting textOpacity to a camera function should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
+ @"textOpacity should round-trip camera functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.textOpacity = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
+ @"Setting textOpacity to a source function should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
+ @"textOpacity should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.textOpacity = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
+ @"Setting textOpacity to a composite function should update text-opacity.");
+ XCTAssertEqualObjects(layer.textOpacity, functionStyleValue,
+ @"textOpacity should round-trip composite functions.");
+
+
layer.textOpacity = nil;
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@"Unsetting textOpacity should return text-opacity to the default value.");
XCTAssertEqualObjects(layer.textOpacity, defaultStyleValue,
@"textOpacity should return the default value after being unset.");
}
-
+
// text-translate
{
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@"text-translate should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslation;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:
#if TARGET_OS_IPHONE
[NSValue valueWithCGVector:CGVectorMake(1, 1)]
#else
[NSValue valueWithMGLVector:CGVectorMake(1, -1)]
#endif
];
- layer.textTranslation = styleValue;
+ layer.textTranslation = constantStyleValue;
mbgl::style::PropertyValue<std::array<float, 2>> propertyValue = { { 1, 1 } };
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
@"Setting textTranslation to a constant value should update text-translate.");
- XCTAssertEqualObjects(layer.textTranslation, styleValue,
+ XCTAssertEqualObjects(layer.textTranslation, constantStyleValue,
@"textTranslation should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textTranslation = functionStyleValue;
+
+ mbgl::style::IntervalStops<std::array<float, 2>> intervalStops = { {{18, { 1, 1 }}} };
+ propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textTranslation = styleValue;
- propertyValue = { mbgl::style::Function<std::array<float, 2>> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
- @"Setting textTranslation to a function should update text-translate.");
- XCTAssertEqualObjects(layer.textTranslation, styleValue,
- @"textTranslation should round-trip functions.");
-
+ @"Setting textTranslation to a camera function should update text-translate.");
+ XCTAssertEqualObjects(layer.textTranslation, functionStyleValue,
+ @"textTranslation should round-trip camera functions.");
+
+
+
layer.textTranslation = nil;
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@"Unsetting textTranslation should return text-translate to the default value.");
XCTAssertEqualObjects(layer.textTranslation, defaultStyleValue,
@"textTranslation should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textTranslation = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
-
+
// text-translate-anchor
{
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
@"text-translate-anchor should be unset initially.");
MGLStyleValue<NSValue *> *defaultStyleValue = layer.textTranslationAnchor;
-
- MGLStyleValue<NSValue *> *styleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]];
- layer.textTranslationAnchor = styleValue;
+
+ MGLStyleValue<NSValue *> *constantStyleValue = [MGLStyleValue<NSValue *> valueWithRawValue:[NSValue valueWithMGLTextTranslationAnchor:MGLTextTranslationAnchorViewport]];
+ layer.textTranslationAnchor = constantStyleValue;
mbgl::style::PropertyValue<mbgl::style::TranslateAnchorType> propertyValue = { mbgl::style::TranslateAnchorType::Viewport };
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
@"Setting textTranslationAnchor to a constant value should update text-translate-anchor.");
- XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue,
+ XCTAssertEqualObjects(layer.textTranslationAnchor, constantStyleValue,
@"textTranslationAnchor should round-trip constant values.");
+
+ MGLStyleValue<NSValue *> * functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval cameraStops:@{@18: constantStyleValue} options:nil];
+ layer.textTranslationAnchor = functionStyleValue;
+
+ mbgl::style::IntervalStops<mbgl::style::TranslateAnchorType> intervalStops = { {{18, mbgl::style::TranslateAnchorType::Viewport}} };
+ propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
- styleValue = [MGLStyleValue<NSValue *> valueWithStops:@{
- @18: styleValue,
- }];
- layer.textTranslationAnchor = styleValue;
- propertyValue = { mbgl::style::Function<mbgl::style::TranslateAnchorType> {
- {{ 18, propertyValue.asConstant() }},
- 1,
- }};
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
- @"Setting textTranslationAnchor to a function should update text-translate-anchor.");
- XCTAssertEqualObjects(layer.textTranslationAnchor, styleValue,
- @"textTranslationAnchor should round-trip functions.");
-
+ @"Setting textTranslationAnchor to a camera function should update text-translate-anchor.");
+ XCTAssertEqualObjects(layer.textTranslationAnchor, functionStyleValue,
+ @"textTranslationAnchor should round-trip camera functions.");
+
+
+
layer.textTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
@"Unsetting textTranslationAnchor should return text-translate-anchor to the default value.");
XCTAssertEqualObjects(layer.textTranslationAnchor, defaultStyleValue,
@"textTranslationAnchor should return the default value after being unset.");
+
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
+ functionStyleValue = [MGLStyleValue<NSValue *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
+ XCTAssertThrowsSpecificNamed(layer.textTranslationAnchor = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
}
}
diff --git a/platform/darwin/test/MGLTileSetTests.mm b/platform/darwin/test/MGLTileSetTests.mm
index 06901a0e96..40eab5f974 100644
--- a/platform/darwin/test/MGLTileSetTests.mm
+++ b/platform/darwin/test/MGLTileSetTests.mm
@@ -15,40 +15,40 @@
// a tile set that provides an mbgl tile set
NSArray *tileURLTemplates = @[@"tile.1", @"tile.2", @"tile.3"];
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, nil);
-
+
// has the correct URL templates
XCTAssertEqual(tileSet.tiles.size(), 3);
XCTAssertEqual(tileSet.tiles[0], "tile.1");
XCTAssertEqual(tileSet.tiles[1], "tile.2");
XCTAssertEqual(tileSet.tiles[2], "tile.3");
-
+
// has the default scheme
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::XYZ);
-
+
// when the tile set has no min or max zoom level set
// the mbgl object has default values for min and max zoom level
XCTAssertEqual(tileSet.zoomRange.min, 0);
XCTAssertEqual(tileSet.zoomRange.max, 22);
-
+
// when the tile set has min and/or max zoom level set
tileSet = MGLTileSetFromTileURLTemplates(@[@"tile.1"], @{
MGLTileSourceOptionMinimumZoomLevel: @1,
MGLTileSourceOptionMaximumZoomLevel: @2,
});
-
+
// the mbgl object reflects the set values for min and max zoom level
XCTAssertEqual(tileSet.zoomRange.min, 1);
XCTAssertEqual(tileSet.zoomRange.max, 2);
-
+
// when the tile set has an attribution
NSString *attribution = @"my tileset © ©️🎈";
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionAttributionHTMLString: attribution,
});
-
+
// the attribution is reflected by the mbgl tileset
XCTAssertEqual(tileSet.attribution, attribution.UTF8String);
-
+
// when the tile set has attribution infos
MGLAttributionInfo *mapboxInfo = [[MGLAttributionInfo alloc] initWithTitle:[[NSAttributedString alloc] initWithString:@"Mapbox"]
URL:[NSURL URLWithString:@"https://www.mapbox.com/"]];
@@ -59,7 +59,7 @@
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionAttributionInfos: @[mapboxInfo, glInfo],
});
-
+
// the attribution is reflected by the mbgl tileset
#if TARGET_OS_IPHONE
NSString *html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt\">"
@@ -71,21 +71,21 @@
@"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica; background-color: #ff2600\">GL</font>\n");
#endif
XCTAssertEqualObjects(@(tileSet.attribution.c_str()), html);
-
+
// when the tile coordinate system is changed using an NSNumber
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionTileCoordinateSystem: @(MGLTileCoordinateSystemTMS),
});
-
+
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
-
+
// when the tile coordinate system is changed using an NSValue
MGLTileCoordinateSystem tms = MGLTileCoordinateSystemTMS;
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionTileCoordinateSystem: [NSValue value:&tms withObjCType:@encode(MGLTileCoordinateSystem)],
});
-
+
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
}
diff --git a/platform/default/bidi.cpp b/platform/default/bidi.cpp
index 25b4dbe3a7..08a02ee60f 100644
--- a/platform/default/bidi.cpp
+++ b/platform/default/bidi.cpp
@@ -18,7 +18,7 @@ public:
UBiDi* bidiText = nullptr;
UBiDi* bidiLine = nullptr;
};
-
+
BiDi::BiDi() : impl(std::make_unique<BiDiImpl>()) {}
BiDi::~BiDi() = default;
@@ -36,8 +36,9 @@ std::u16string applyArabicShaping(const std::u16string& input) {
// Pre-flighting will always set U_BUFFER_OVERFLOW_ERROR
errorCode = U_ZERO_ERROR;
- auto outputText = std::make_unique<UChar[]>(outputLength);
- u_shapeArabic(input.c_str(), static_cast<int32_t>(input.size()), outputText.get(), outputLength,
+ std::u16string outputText(outputLength, 0);
+
+ u_shapeArabic(input.c_str(), static_cast<int32_t>(input.size()), &outputText[0], outputLength,
(U_SHAPE_LETTERS_SHAPE & U_SHAPE_LETTERS_MASK) |
(U_SHAPE_TEXT_DIRECTION_LOGICAL & U_SHAPE_TEXT_DIRECTION_MASK),
&errorCode);
@@ -46,7 +47,7 @@ std::u16string applyArabicShaping(const std::u16string& input) {
if (U_FAILURE(errorCode))
return input;
- return std::u16string(outputText.get(), outputLength);
+ return outputText;
}
void BiDi::mergeParagraphLineBreaks(std::set<size_t>& lineBreakPoints) {
@@ -73,6 +74,8 @@ std::vector<std::u16string> BiDi::applyLineBreaking(std::set<std::size_t> lineBr
mergeParagraphLineBreaks(lineBreakPoints);
std::vector<std::u16string> transformedLines;
+ transformedLines.reserve(lineBreakPoints.size());
+
std::size_t start = 0;
for (std::size_t lineBreakPoint : lineBreakPoints) {
transformedLines.push_back(getLine(start, lineBreakPoint));
@@ -108,12 +111,12 @@ std::u16string BiDi::getLine(std::size_t start, std::size_t end) {
// Setting UBIDI_INSERT_LRM_FOR_NUMERIC would require
// ubidi_getLength(pBiDi)+2*ubidi_countRuns(pBiDi)
const int32_t outputLength = ubidi_getProcessedLength(impl->bidiLine);
- auto outputText = std::make_unique<UChar[]>(outputLength);
+ std::u16string outputText(outputLength, 0);
// UBIDI_DO_MIRRORING: Apply unicode mirroring of characters like parentheses
// UBIDI_REMOVE_BIDI_CONTROLS: Now that all the lines are set, remove control characters so that
// they don't show up on screen (some fonts have glyphs representing them)
- ubidi_writeReordered(impl->bidiLine, outputText.get(), outputLength,
+ ubidi_writeReordered(impl->bidiLine, &outputText[0], outputLength,
UBIDI_DO_MIRRORING | UBIDI_REMOVE_BIDI_CONTROLS, &errorCode);
if (U_FAILURE(errorCode)) {
@@ -121,7 +124,7 @@ std::u16string BiDi::getLine(std::size_t start, std::size_t end) {
u_errorName(errorCode));
}
- return std::u16string(outputText.get(), outputLength);
+ return outputText;
}
} // end namespace mbgl
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index c4222b5a12..20a3eadc8b 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -29,11 +29,11 @@ public:
Impl(const std::string& cachePath, uint64_t maximumCacheSize)
: offlineDatabase(cachePath, maximumCacheSize) {
}
-
+
void setAPIBaseURL(const std::string& url) {
onlineFileSource.setAPIBaseURL(url);
}
-
+
std::string getAPIBaseURL() const{
return onlineFileSource.getAPIBaseURL();
}
@@ -46,6 +46,10 @@ public:
return onlineFileSource.getAccessToken();
}
+ void setResourceTransform(OnlineFileSource::ResourceTransform&& transform) {
+ onlineFileSource.setResourceTransform(std::move(transform));
+ }
+
void listRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
try {
callback({}, offlineDatabase.listRegions());
@@ -63,7 +67,7 @@ public:
callback(std::current_exception(), {});
}
}
-
+
void updateMetadata(const int64_t regionID,
const OfflineRegionMetadata& metadata,
std::function<void (std::exception_ptr, optional<OfflineRegionMetadata>)> callback) {
@@ -172,19 +176,30 @@ DefaultFileSource::DefaultFileSource(const std::string& cachePath,
DefaultFileSource::~DefaultFileSource() = default;
void DefaultFileSource::setAPIBaseURL(const std::string& baseURL) {
- thread->invokeSync(&Impl::setAPIBaseURL, baseURL);
+ thread->invoke(&Impl::setAPIBaseURL, baseURL);
+ cachedBaseURL = baseURL;
}
-
+
std::string DefaultFileSource::getAPIBaseURL() const {
- return thread->invokeSync(&Impl::getAPIBaseURL);
+ return cachedBaseURL;
}
-
+
void DefaultFileSource::setAccessToken(const std::string& accessToken) {
- thread->invokeSync(&Impl::setAccessToken, accessToken);
+ thread->invoke(&Impl::setAccessToken, accessToken);
+ cachedAccessToken = accessToken;
}
std::string DefaultFileSource::getAccessToken() const {
- return thread->invokeSync(&Impl::getAccessToken);
+ return cachedAccessToken;
+}
+
+void DefaultFileSource::setResourceTransform(std::function<std::string(Resource::Kind, std::string&&)> transform) {
+ auto loop = util::RunLoop::Get();
+ thread->invoke(&Impl::setResourceTransform, [loop, transform](Resource::Kind kind_, std::string&& url_, auto callback_) {
+ return loop->invokeWithCallback([transform](Resource::Kind kind, std::string&& url, auto callback) {
+ callback(transform(kind, std::move(url)));
+ }, kind_, std::move(url_), callback_);
+ });
}
std::unique_ptr<AsyncRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
@@ -248,6 +263,14 @@ void DefaultFileSource::setOfflineMapboxTileCountLimit(uint64_t limit) const {
thread->invokeSync(&Impl::setOfflineMapboxTileCountLimit, limit);
}
+void DefaultFileSource::pause() {
+ thread->pause();
+}
+
+void DefaultFileSource::resume() {
+ thread->resume();
+}
+
// For testing only:
void DefaultFileSource::put(const Resource& resource, const Response& response) {
diff --git a/platform/default/headless_backend_osmesa.cpp b/platform/default/headless_backend_osmesa.cpp
index 081bddf170..8ec6079bd0 100644
--- a/platform/default/headless_backend_osmesa.cpp
+++ b/platform/default/headless_backend_osmesa.cpp
@@ -12,9 +12,6 @@ struct OSMesaImpl : public HeadlessBackend::Impl {
}
~OSMesaImpl() {
- if (glContext != OSMesaGetCurrentContext()) {
- activateContext();
- }
OSMesaDestroyContext(glContext);
}
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index 84db1e9c71..ad9d83a08d 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -2,78 +2,8 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/premultiply.hpp>
-#include <png.h>
-
-template<size_t max, typename... Args>
-static std::string sprintf(const char *msg, Args... args) {
- char res[max];
- int len = snprintf(res, sizeof(res), msg, args...);
- return std::string(res, len);
-}
-
-const static bool png_version_check __attribute__((unused)) = []() {
- const png_uint_32 version = png_access_version_number();
- if (version != PNG_LIBPNG_VER) {
- throw std::runtime_error(sprintf<96>(
- "libpng version mismatch: headers report %d.%d.%d, but library reports %d.%d.%d",
- PNG_LIBPNG_VER / 10000, (PNG_LIBPNG_VER / 100) % 100, PNG_LIBPNG_VER % 100,
- version / 10000, (version / 100) % 100, version % 100));
- }
- return true;
-}();
-
namespace mbgl {
-std::string encodePNG(const PremultipliedImage& pre) {
- PremultipliedImage copy(pre.size);
- std::copy(pre.data.get(), pre.data.get() + pre.bytes(), copy.data.get());
-
- UnassociatedImage src = util::unpremultiply(std::move(copy));
-
- png_voidp error_ptr = nullptr;
- png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, error_ptr, nullptr, nullptr);
- if (!png_ptr) {
- throw std::runtime_error("couldn't create png_ptr");
- }
-
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (!png_ptr) {
- png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
- throw std::runtime_error("couldn't create info_ptr");
- }
-
- png_set_IHDR(png_ptr, info_ptr, src.size.width, src.size.height, 8, PNG_COLOR_TYPE_RGB_ALPHA,
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-
- jmp_buf *jmp_context = (jmp_buf *)png_get_error_ptr(png_ptr);
- if (jmp_context) {
- png_destroy_write_struct(&png_ptr, &info_ptr);
- throw std::runtime_error("png error");
- }
-
- std::string result;
- png_set_write_fn(png_ptr, &result, [](png_structp png_ptr_, png_bytep data, png_size_t length) {
- std::string *out = static_cast<std::string *>(png_get_io_ptr(png_ptr_));
- out->append(reinterpret_cast<char *>(data), length);
- }, nullptr);
-
- struct ptrs {
- ptrs(size_t count) : rows(new png_bytep[count]) {}
- ~ptrs() { delete[] rows; }
- png_bytep *rows = nullptr;
- } pointers(src.size.height);
-
- for (size_t i = 0; i < src.size.height; i++) {
- pointers.rows[i] = src.data.get() + src.stride() * i;
- }
-
- png_set_rows(png_ptr, info_ptr, pointers.rows);
- png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- return result;
-}
-
#if !defined(__ANDROID__) && !defined(__APPLE__)
PremultipliedImage decodeWebP(const uint8_t*, size_t);
#endif // !defined(__ANDROID__) && !defined(__APPLE__)
diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp
index 78c74f2fd7..c5e9d880c0 100644
--- a/platform/default/jpeg_reader.cpp
+++ b/platform/default/jpeg_reader.cpp
@@ -35,7 +35,7 @@ static boolean fill_input_buffer(j_decompress_ptr cinfo) {
}
static void skip(j_decompress_ptr cinfo, long count) {
- if (count <= 0) return; //A zero or negative skip count should be treated as a no-op.
+ if (count <= 0) return; // A zero or negative skip count should be treated as a no-op.
jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
if (wrap->manager.bytes_in_buffer > 0 && count < static_cast<long>(wrap->manager.bytes_in_buffer))
@@ -48,7 +48,7 @@ static void skip(j_decompress_ptr cinfo, long count) {
wrap->stream->seekg(count - wrap->manager.bytes_in_buffer, std::ios_base::cur);
// trigger buffer fill
wrap->manager.next_input_byte = nullptr;
- wrap->manager.bytes_in_buffer = 0; //bytes_in_buffer may be zero on return.
+ wrap->manager.bytes_in_buffer = 0; // bytes_in_buffer may be zero on return.
}
}
diff --git a/platform/default/local_file_source.cpp b/platform/default/local_file_source.cpp
index 5686b453dc..93b42f5fa0 100644
--- a/platform/default/local_file_source.cpp
+++ b/platform/default/local_file_source.cpp
@@ -14,7 +14,7 @@ namespace {
const char* protocol = "file://";
const std::size_t protocolLength = 7;
-
+
} // namespace
namespace mbgl {
@@ -22,7 +22,7 @@ namespace mbgl {
class LocalFileSource::Impl {
public:
void request(const std::string& url, FileSource::Callback callback) {
- //Cut off the protocol
+ // Cut off the protocol
std::string path = mbgl::util::percentDecode(url.substr(protocolLength));
Response response;
@@ -58,7 +58,7 @@ LocalFileSource::~LocalFileSource() = default;
std::unique_ptr<AsyncRequest> LocalFileSource::request(const Resource& resource, Callback callback) {
return thread->invokeWithCallback(&Impl::request, resource.url, callback);
}
-
+
bool LocalFileSource::acceptsURL(const std::string& url) {
return url.compare(0, protocolLength, protocol) == 0;
}
diff --git a/platform/default/mbgl/gl/headless_backend.cpp b/platform/default/mbgl/gl/headless_backend.cpp
index 0bfdf11c98..c105fd6b84 100644
--- a/platform/default/mbgl/gl/headless_backend.cpp
+++ b/platform/default/mbgl/gl/headless_backend.cpp
@@ -1,5 +1,7 @@
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/headless_display.hpp>
+#include <mbgl/gl/context.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <cassert>
#include <stdexcept>
@@ -8,17 +10,15 @@
namespace mbgl {
HeadlessBackend::HeadlessBackend() {
- activate();
}
HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_)
: display(std::move(display_)) {
- activate();
}
HeadlessBackend::~HeadlessBackend() {
- deactivate();
- destroyContext();
+ BackendScope scope(*this);
+ context.reset();
}
void HeadlessBackend::activate() {
@@ -31,7 +31,8 @@ void HeadlessBackend::activate() {
createContext();
}
- activateContext();
+ assert(hasContext());
+ impl->activateContext();
if (!extensionsLoaded) {
gl::InitializeExtensions(initializeExtension);
@@ -40,7 +41,8 @@ void HeadlessBackend::activate() {
}
void HeadlessBackend::deactivate() {
- deactivateContext();
+ assert(hasContext());
+ impl->deactivateContext();
active = false;
}
@@ -48,21 +50,6 @@ void HeadlessBackend::invalidate() {
assert(false);
}
-void HeadlessBackend::destroyContext() {
- assert(hasContext());
- impl.reset();
-}
-
-void HeadlessBackend::activateContext() {
- assert(hasContext());
- impl->activateContext();
-}
-
-void HeadlessBackend::deactivateContext() {
- assert(hasContext());
- impl->deactivateContext();
-}
-
void HeadlessBackend::notifyMapChange(MapChange change) {
if (mapChangeCallback) {
mapChangeCallback(change);
diff --git a/platform/default/mbgl/gl/headless_backend.hpp b/platform/default/mbgl/gl/headless_backend.hpp
index da8c55e044..e632d0feb6 100644
--- a/platform/default/mbgl/gl/headless_backend.hpp
+++ b/platform/default/mbgl/gl/headless_backend.hpp
@@ -18,8 +18,6 @@ public:
~HeadlessBackend() override;
void invalidate() override;
- void activate() override;
- void deactivate() override;
void notifyMapChange(MapChange) override;
void setMapChangeCallback(std::function<void(MapChange)>&& cb) { mapChangeCallback = std::move(cb); }
@@ -34,17 +32,14 @@ private:
// Implementation specific functions
static gl::glProc initializeExtension(const char*);
+ void activate() override;
+ void deactivate() override;
+
bool hasContext() const { return bool(impl); }
bool hasDisplay();
void createContext();
-private:
- void destroyContext();
-
- void activateContext();
- void deactivateContext();
-
std::unique_ptr<Impl> impl;
std::shared_ptr<HeadlessDisplay> display;
diff --git a/platform/default/mbgl/gl/offscreen_view.cpp b/platform/default/mbgl/gl/offscreen_view.cpp
index 16faf6a4a9..a517cefad9 100644
--- a/platform/default/mbgl/gl/offscreen_view.cpp
+++ b/platform/default/mbgl/gl/offscreen_view.cpp
@@ -1,30 +1,64 @@
#include <mbgl/gl/offscreen_view.hpp>
#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/framebuffer.hpp>
+#include <mbgl/gl/renderbuffer.hpp>
+#include <mbgl/util/optional.hpp>
#include <cstring>
#include <cassert>
namespace mbgl {
-OffscreenView::OffscreenView(gl::Context& context_, const Size size_)
- : size(std::move(size_)), context(context_) {
- assert(size);
-}
+class OffscreenView::Impl {
+public:
+ Impl(gl::Context& context_, const Size size_) : context(context_), size(std::move(size_)) {
+ assert(size);
+ }
-void OffscreenView::bind() {
- if (!framebuffer) {
- color = context.createRenderbuffer<gl::RenderbufferType::RGBA>(size);
- depthStencil = context.createRenderbuffer<gl::RenderbufferType::DepthStencil>(size);
- framebuffer = context.createFramebuffer(*color, *depthStencil);
- } else {
- context.bindFramebuffer = framebuffer->framebuffer;
+ void bind() {
+ if (!framebuffer) {
+ color = context.createRenderbuffer<gl::RenderbufferType::RGBA>(size);
+ depthStencil = context.createRenderbuffer<gl::RenderbufferType::DepthStencil>(size);
+ framebuffer = context.createFramebuffer(*color, *depthStencil);
+ } else {
+ context.bindFramebuffer = framebuffer->framebuffer;
+ }
+
+ context.viewport = { 0, 0, size };
+ }
+
+ PremultipliedImage readStillImage() {
+ return context.readFramebuffer<PremultipliedImage>(size);
+ }
+
+ const Size& getSize() const {
+ return size;
}
- context.viewport = { 0, 0, size };
+private:
+ gl::Context& context;
+ const Size size;
+ optional<gl::Framebuffer> framebuffer;
+ optional<gl::Renderbuffer<gl::RenderbufferType::RGBA>> color;
+ optional<gl::Renderbuffer<gl::RenderbufferType::DepthStencil>> depthStencil;
+};
+
+OffscreenView::OffscreenView(gl::Context& context, const Size size)
+ : impl(std::make_unique<Impl>(context, std::move(size))) {
+}
+
+OffscreenView::~OffscreenView() = default;
+
+void OffscreenView::bind() {
+ impl->bind();
}
PremultipliedImage OffscreenView::readStillImage() {
- return context.readFramebuffer<PremultipliedImage>(size);
+ return impl->readStillImage();
+}
+
+const Size& OffscreenView::getSize() const {
+ return impl->getSize();
}
} // namespace mbgl
diff --git a/platform/default/mbgl/gl/offscreen_view.hpp b/platform/default/mbgl/gl/offscreen_view.hpp
index 0e839e14cc..bf1a9889cd 100644
--- a/platform/default/mbgl/gl/offscreen_view.hpp
+++ b/platform/default/mbgl/gl/offscreen_view.hpp
@@ -1,9 +1,6 @@
#pragma once
#include <mbgl/map/view.hpp>
-#include <mbgl/gl/framebuffer.hpp>
-#include <mbgl/gl/renderbuffer.hpp>
-#include <mbgl/util/optional.hpp>
#include <mbgl/util/image.hpp>
namespace mbgl {
@@ -15,19 +12,17 @@ class Context;
class OffscreenView : public View {
public:
OffscreenView(gl::Context&, Size size = { 256, 256 });
+ ~OffscreenView();
void bind() override;
PremultipliedImage readStillImage();
-public:
- const Size size;
+ const Size& getSize() const;
private:
- gl::Context& context;
- optional<gl::Framebuffer> framebuffer;
- optional<gl::Renderbuffer<gl::RenderbufferType::RGBA>> color;
- optional<gl::Renderbuffer<gl::RenderbufferType::DepthStencil>> depthStencil;
+ class Impl;
+ const std::unique_ptr<Impl> impl;
};
} // namespace mbgl
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 49359dbd39..02736f10a4 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -7,7 +7,6 @@
#include <mbgl/util/logging.hpp>
#include "sqlite3.hpp"
-#include <sqlite3.h>
namespace mbgl {
@@ -57,13 +56,13 @@ void OfflineDatabase::ensureSchema() {
removeExisting();
connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
} catch (mapbox::sqlite::Exception& ex) {
- if (ex.code != SQLITE_CANTOPEN && ex.code != SQLITE_NOTADB) {
+ if (ex.code != mapbox::sqlite::Exception::Code::CANTOPEN && ex.code != mapbox::sqlite::Exception::Code::NOTADB) {
Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
throw;
}
try {
- if (ex.code == SQLITE_NOTADB) {
+ if (ex.code == mapbox::sqlite::Exception::Code::NOTADB) {
removeExisting();
}
connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
@@ -313,7 +312,7 @@ bool OfflineDatabase::putResource(const Resource& resource,
}
update->run();
- if (db->changes() != 0) {
+ if (update->changes() != 0) {
transaction.commit();
return false;
}
@@ -502,7 +501,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
}
update->run();
- if (db->changes() != 0) {
+ if (update->changes() != 0) {
transaction.commit();
return false;
}
@@ -567,7 +566,7 @@ OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& defin
stmt->bindBlob(2, metadata);
stmt->run();
- return OfflineRegion(db->lastInsertRowid(), definition, metadata);
+ return OfflineRegion(stmt->lastInsertRowId(), definition, metadata);
}
OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) {
@@ -579,7 +578,7 @@ OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, co
stmt->bindBlob(1, metadata);
stmt->bind(2, regionID);
stmt->run();
-
+
return metadata;
}
@@ -656,7 +655,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
insert->bind(6, tile.z);
insert->run();
- if (db->changes() == 0) {
+ if (insert->changes() == 0) {
return false;
}
@@ -693,7 +692,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
insert->bind(2, resource.url);
insert->run();
- if (db->changes() == 0) {
+ if (insert->changes() == 0) {
return false;
}
@@ -816,7 +815,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
return false;
}
Timestamp accessed = accessedStmt->get<Timestamp>(0);
-
+
// clang-format off
Statement stmt1 = getStatement(
"DELETE FROM resources "
@@ -830,7 +829,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
// clang-format on
stmt1->bind(1, accessed);
stmt1->run();
- uint64_t changes1 = db->changes();
+ uint64_t changes1 = stmt1->changes();
// clang-format off
Statement stmt2 = getStatement(
@@ -845,7 +844,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
// clang-format on
stmt2->bind(1, accessed);
stmt2->run();
- uint64_t changes2 = db->changes();
+ uint64_t changes2 = stmt2->changes();
// The cached value of offlineTileCount does not need to be updated
// here because only non-offline tiles can be removed by eviction.
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 875677f7cf..57ffcee4eb 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -41,7 +41,7 @@ public:
const OfflineRegionMetadata&);
OfflineRegionMetadata updateMetadata(const int64_t regionID, const OfflineRegionMetadata&);
-
+
void deleteRegion(OfflineRegion&&);
// Return value is (response, stored size)
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index 3edc75845c..c8aa98d874 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -252,7 +252,7 @@ void OfflineDownload::ensureResource(const Resource& resource,
auto workRequestsIt = requests.insert(requests.begin(), nullptr);
*workRequestsIt = util::RunLoop::Get()->invokeCancellable([=]() {
requests.erase(workRequestsIt);
-
+
auto getResourceSizeInDatabase = [&] () -> optional<int64_t> {
if (!callback) {
return offlineDatabase.hasRegionResource(id, resource);
@@ -264,7 +264,7 @@ void OfflineDownload::ensureResource(const Resource& resource,
callback(response->first);
return response->second;
};
-
+
optional<int64_t> offlineResponse = getResourceSizeInDatabase();
if (offlineResponse) {
status.completedResourceCount++;
diff --git a/platform/default/mbgl/storage/offline_download.hpp b/platform/default/mbgl/storage/offline_download.hpp
index f29a053a87..c978ded931 100644
--- a/platform/default/mbgl/storage/offline_download.hpp
+++ b/platform/default/mbgl/storage/offline_download.hpp
@@ -47,7 +47,7 @@ private:
*/
void ensureResource(const Resource&, std::function<void (Response)> = {});
bool checkTileCountLimit(const Resource& resource);
-
+
int64_t id;
OfflineRegionDefinition definition;
OfflineDatabase& offlineDatabase;
diff --git a/platform/default/mbgl/util/default_thread_pool.cpp b/platform/default/mbgl/util/default_thread_pool.cpp
index 92c0f06745..d3950bb8aa 100644
--- a/platform/default/mbgl/util/default_thread_pool.cpp
+++ b/platform/default/mbgl/util/default_thread_pool.cpp
@@ -1,12 +1,16 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/actor/mailbox.hpp>
+#include <mbgl/util/platform.hpp>
+#include <mbgl/util/string.hpp>
namespace mbgl {
ThreadPool::ThreadPool(std::size_t count) {
threads.reserve(count);
for (std::size_t i = 0; i < count; ++i) {
- threads.emplace_back([this] () {
+ threads.emplace_back([this, i]() {
+ platform::setCurrentThreadName(std::string{ "Worker " } + util::toString(i + 1));
+
while (true) {
std::unique_lock<std::mutex> lock(mutex);
diff --git a/platform/default/mbgl/util/shared_thread_pool.cpp b/platform/default/mbgl/util/shared_thread_pool.cpp
new file mode 100644
index 0000000000..7a42df21de
--- /dev/null
+++ b/platform/default/mbgl/util/shared_thread_pool.cpp
@@ -0,0 +1,14 @@
+#include "shared_thread_pool.hpp"
+
+namespace mbgl {
+
+std::shared_ptr<ThreadPool> sharedThreadPool() {
+ static std::weak_ptr<ThreadPool> weak;
+ auto pool = weak.lock();
+ if (!pool) {
+ weak = pool = std::make_shared<ThreadPool>(4);
+ }
+ return pool;
+}
+
+} // namespace mbgl
diff --git a/platform/default/mbgl/util/shared_thread_pool.hpp b/platform/default/mbgl/util/shared_thread_pool.hpp
new file mode 100644
index 0000000000..04a3cb58d5
--- /dev/null
+++ b/platform/default/mbgl/util/shared_thread_pool.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <mbgl/util/default_thread_pool.hpp>
+
+namespace mbgl {
+
+std::shared_ptr<ThreadPool> sharedThreadPool();
+
+} // namespace mbgl
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index 0f2bc5ff56..a72b6f4efc 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -31,6 +31,7 @@ public:
~OnlineFileRequest() override;
void networkIsReachableAgain();
+ void schedule();
void schedule(optional<Timestamp> expires);
void completed(Response);
@@ -64,6 +65,19 @@ public:
void add(OnlineFileRequest* request) {
allRequests.insert(request);
+ if (resourceTransform) {
+ // When there's a Resource transform callback set, replace the resource with the
+ // transformed one before proceeding to schedule the request.
+ request->request =
+ resourceTransform(request->resource.kind, std::move(request->resource.url),
+ [request](std::string&& url) {
+ request->request.release();
+ request->resource.url = std::move(url);
+ request->schedule();
+ });
+ } else {
+ request->schedule();
+ }
}
void remove(OnlineFileRequest* request) {
@@ -122,15 +136,19 @@ public:
activateRequest(request);
assert(pendingRequestsMap.size() == pendingRequestsList.size());
}
-
+
bool isPending(OnlineFileRequest* request) {
return pendingRequestsMap.find(request) != pendingRequestsMap.end();
}
-
+
bool isActive(OnlineFileRequest* request) {
return activeRequests.find(request) != activeRequests.end();
}
+ void setResourceTransform(ResourceTransform&& transform) {
+ resourceTransform = std::move(transform);
+ }
+
private:
void networkIsReachableAgain() {
for (auto& request : allRequests) {
@@ -138,6 +156,8 @@ private:
}
}
+ ResourceTransform resourceTransform;
+
/**
* The lifetime of a request is:
*
@@ -196,12 +216,18 @@ std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource
return std::make_unique<OnlineFileRequest>(std::move(res), std::move(callback), *impl);
}
+void OnlineFileSource::setResourceTransform(ResourceTransform&& transform) {
+ impl->setResourceTransform(std::move(transform));
+}
+
OnlineFileRequest::OnlineFileRequest(Resource resource_, Callback callback_, OnlineFileSource::Impl& impl_)
: impl(impl_),
resource(std::move(resource_)),
callback(std::move(callback_)) {
impl.add(this);
+}
+void OnlineFileRequest::schedule() {
// Force an immediate first request if we don't have an expiration time.
if (resource.priorExpires) {
schedule(resource.priorExpires);
diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp
index 5ae74d74db..d694f43405 100644
--- a/platform/default/png_reader.cpp
+++ b/platform/default/png_reader.cpp
@@ -11,6 +11,24 @@ extern "C"
#include <png.h>
}
+template<size_t max, typename... Args>
+static std::string sprintf(const char *msg, Args... args) {
+ char res[max];
+ int len = snprintf(res, sizeof(res), msg, args...);
+ return std::string(res, len);
+}
+
+const static bool png_version_check __attribute__((unused)) = []() {
+ const png_uint_32 version = png_access_version_number();
+ if (version != PNG_LIBPNG_VER) {
+ throw std::runtime_error(sprintf<96>(
+ "libpng version mismatch: headers report %d.%d.%d, but library reports %d.%d.%d",
+ PNG_LIBPNG_VER / 10000, (PNG_LIBPNG_VER / 100) % 100, PNG_LIBPNG_VER % 100,
+ version / 10000, (version / 100) % 100, version % 100));
+ }
+ return true;
+}();
+
namespace mbgl {
static void user_error_fn(png_structp, png_const_charp error_msg) {
diff --git a/platform/default/png_writer.cpp b/platform/default/png_writer.cpp
new file mode 100644
index 0000000000..9ef9052158
--- /dev/null
+++ b/platform/default/png_writer.cpp
@@ -0,0 +1,80 @@
+#include <mbgl/util/compression.hpp>
+#include <mbgl/util/image.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#include <boost/crc.hpp>
+#pragma GCC diagnostic pop
+
+#include <cassert>
+#include <cstring>
+
+#define NETWORK_BYTE_UINT32(value) \
+ char(value >> 24), char(value >> 16), char(value >> 8), char(value >> 0)
+
+namespace {
+
+void addChunk(std::string& png, const char* type, const char* data = "", const uint32_t size = 0) {
+ assert(strlen(type) == 4);
+
+ // Checksum encompasses type + data
+ boost::crc_32_type checksum;
+ checksum.process_bytes(type, 4);
+ checksum.process_bytes(data, size);
+
+ const char length[4] = { NETWORK_BYTE_UINT32(size) };
+ const char crc[4] = { NETWORK_BYTE_UINT32(checksum.checksum()) };
+
+ png.reserve(png.size() + 4 /* length */ + 4 /* type */ + size + 4 /* CRC */);
+ png.append(length, 4);
+ png.append(type, 4);
+ png.append(data, size);
+ png.append(crc, 4);
+}
+
+} // namespace
+
+namespace mbgl {
+
+// Encode PNGs without libpng.
+std::string encodePNG(const PremultipliedImage& pre) {
+ // Make copy of the image so that we can unpremultiply it.
+ const auto src = util::unpremultiply(pre.clone());
+
+ // PNG magic bytes
+ const char preamble[8] = { char(0x89), 'P', 'N', 'G', '\r', '\n', 0x1a, '\n' };
+
+ // IHDR chunk for our RGBA image.
+ const char ihdr[13] = {
+ NETWORK_BYTE_UINT32(src.size.width), // width
+ NETWORK_BYTE_UINT32(src.size.height), // height
+ 8, // bit depth == 8 bits
+ 6, // color type == RGBA
+ 0, // compression method == deflate
+ 0, // filter method == default
+ 0, // interlace method == none
+ };
+
+ // Prepare the (compressed) data chunk.
+ const auto stride = src.stride();
+ std::string idat;
+ for (uint32_t y = 0; y < src.size.height; y++) {
+ // Every scanline needs to be prefixed with one byte that indicates the filter type.
+ idat.append(1, 0); // filter type 0
+ idat.append((const char*)(src.data.get() + y * stride), stride);
+ }
+ idat = util::compress(idat);
+
+ // Assemble the PNG.
+ std::string png;
+ png.reserve((8 /* preamble */) + (12 + 13 /* IHDR */) +
+ (12 + idat.size() /* IDAT */) + (12 /* IEND */));
+ png.append(preamble, 8);
+ addChunk(png, "IHDR", ihdr, 13);
+ addChunk(png, "IDAT", idat.data(), static_cast<uint32_t>(idat.size()));
+ addChunk(png, "IEND");
+ return png;
+}
+
+} // namespace mbgl
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 670b7b84cc..498ac02b2e 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -12,9 +12,73 @@
namespace mapbox {
namespace sqlite {
+class DatabaseImpl {
+public:
+ DatabaseImpl(const char* filename, int flags)
+ {
+ 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) {
+ throw Exception { error, sqlite3_errmsg(db) };
+ }
+ }
+
+ sqlite3* db = nullptr;
+};
+
+class StatementImpl {
+public:
+ StatementImpl(sqlite3* db, const char* sql)
+ {
+ const int error = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
+ if (error != SQLITE_OK) {
+ stmt = nullptr;
+ throw Exception { error, sqlite3_errmsg(db) };
+ }
+ }
+
+ ~StatementImpl()
+ {
+ if (!stmt) return;
+
+ sqlite3_finalize(stmt);
+ }
+
+ void check(int err) {
+ if (err != SQLITE_OK) {
+ throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt)) };
+ }
+ }
+
+ sqlite3_stmt* stmt = nullptr;
+ int64_t lastInsertRowId = 0;
+ int64_t changes = 0;
+};
+
template <typename T>
using optional = std::experimental::optional<T>;
+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);
+ }
+}
+
const static bool sqliteVersionCheck __attribute__((unused)) = []() {
if (sqlite3_libversion_number() / 1000000 != SQLITE_VERSION_NUMBER / 1000000) {
char message[96];
@@ -25,94 +89,61 @@ const static bool sqliteVersionCheck __attribute__((unused)) = []() {
}
// Enable SQLite logging before initializing the database.
- sqlite3_config(SQLITE_CONFIG_LOG, Database::errorLogCallback, nullptr);
+ sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, nullptr);
return true;
}();
-Database::Database(const std::string &filename, int flags) {
- const int err = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr);
- if (err != SQLITE_OK) {
- const auto message = sqlite3_errmsg(db);
- db = nullptr;
- throw Exception { err, message };
- }
+Database::Database(const std::string &filename, int flags)
+ : impl(std::make_unique<DatabaseImpl>(filename.c_str(), flags))
+{
}
Database::Database(Database &&other)
- : db(std::move(other.db)) {}
+ : impl(std::move(other.impl)) {}
Database &Database::operator=(Database &&other) {
- std::swap(db, other.db);
+ std::swap(impl, other.impl);
return *this;
}
Database::~Database() {
- if (db) {
- const int err = sqlite3_close(db);
- if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(db) };
- }
- }
}
Database::operator bool() const {
- return db != nullptr;
-}
-
-void Database::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);
- }
+ return impl.operator bool();
}
void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
- assert(db);
- const int err = sqlite3_busy_timeout(db,
+ assert(impl);
+ const int err = sqlite3_busy_timeout(impl->db,
int(std::min<std::chrono::milliseconds::rep>(timeout.count(), std::numeric_limits<int>::max())));
if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(db) };
+ throw Exception { err, sqlite3_errmsg(impl->db) };
}
}
void Database::exec(const std::string &sql) {
- assert(db);
+ assert(impl);
char *msg = nullptr;
- const int err = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &msg);
+ const int err = sqlite3_exec(impl->db, sql.c_str(), nullptr, nullptr, &msg);
if (msg) {
const std::string message = msg;
sqlite3_free(msg);
throw Exception { err, message };
} else if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(db) };
+ throw Exception { err, sqlite3_errmsg(impl->db) };
}
}
Statement Database::prepare(const char *query) {
- assert(db);
- return Statement(db, query);
-}
-
-int64_t Database::lastInsertRowid() const {
- assert(db);
- return sqlite3_last_insert_rowid(db);
+ assert(impl);
+ return Statement(this, query);
}
-uint64_t Database::changes() const {
- assert(db);
- return sqlite3_changes(db);
-}
-
-Statement::Statement(sqlite3 *db, const char *sql) {
- const int err = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
- if (err != SQLITE_OK) {
- stmt = nullptr;
- throw Exception { err, sqlite3_errmsg(db) };
- }
+Statement::Statement(Database *db, const char *sql)
+ : impl(std::make_unique<StatementImpl>(db->impl->db, sql))
+{
}
Statement::Statement(Statement &&other) {
@@ -120,99 +151,90 @@ Statement::Statement(Statement &&other) {
}
Statement &Statement::operator=(Statement &&other) {
- std::swap(stmt, other.stmt);
+ std::swap(impl, other.impl);
return *this;
}
Statement::~Statement() {
- if (stmt) {
- sqlite3_finalize(stmt);
- }
}
Statement::operator bool() const {
- return stmt != nullptr;
-}
-
-void Statement::check(int err) {
- if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt)) };
- }
+ return impl.operator bool();
}
template <> void Statement::bind(int offset, std::nullptr_t) {
- assert(stmt);
- check(sqlite3_bind_null(stmt, offset));
+ assert(impl);
+ impl->check(sqlite3_bind_null(impl->stmt, offset));
}
template <> void Statement::bind(int offset, int8_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, int16_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, int32_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, int64_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, uint8_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, uint16_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, uint32_t value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, float value) {
- assert(stmt);
- check(sqlite3_bind_double(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_double(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, double value) {
- assert(stmt);
- check(sqlite3_bind_double(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_double(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, bool value) {
- assert(stmt);
- check(sqlite3_bind_int(stmt, offset, value));
+ assert(impl);
+ impl->check(sqlite3_bind_int(impl->stmt, offset, value));
}
template <> void Statement::bind(int offset, const char *value) {
- assert(stmt);
- check(sqlite3_bind_text(stmt, offset, value, -1, SQLITE_STATIC));
+ assert(impl);
+ impl->check(sqlite3_bind_text(impl->stmt, offset, value, -1, SQLITE_STATIC));
}
// 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 7.0: 3.7.13
+// 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.10.2.
+// the first iOS version with 3.8.7+ was 9.0, with 3.8.8.
void Statement::bind(int offset, const char * value, std::size_t length, bool retain) {
- assert(stmt);
+ assert(impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- check(sqlite3_bind_text(stmt, offset, value, int(length),
+ impl->check(sqlite3_bind_text(impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
@@ -221,11 +243,11 @@ void Statement::bind(int offset, const std::string& value, bool retain) {
}
void Statement::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
- assert(stmt);
+ assert(impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- check(sqlite3_bind_blob(stmt, offset, value, int(length),
+ impl->check(sqlite3_bind_blob(impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
@@ -235,9 +257,9 @@ void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool ret
template <>
void Statement::bind(
- int offset, std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> value) {
- assert(stmt);
- check(sqlite3_bind_int64(stmt, offset, std::chrono::system_clock::to_time_t(value)));
+ 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)));
}
template <> void Statement::bind(int offset, optional<std::string> value) {
@@ -260,60 +282,62 @@ void Statement::bind(
}
bool Statement::run() {
- assert(stmt);
- const int err = sqlite3_step(stmt);
+ 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));
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(stmt)) };
+ throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(impl->stmt)) };
} else {
return false;
}
}
template <> int Statement::get(int offset) {
- assert(stmt);
- return sqlite3_column_int(stmt, offset);
+ assert(impl);
+ return sqlite3_column_int(impl->stmt, offset);
}
template <> int64_t Statement::get(int offset) {
- assert(stmt);
- return sqlite3_column_int64(stmt, offset);
+ assert(impl);
+ return sqlite3_column_int64(impl->stmt, offset);
}
template <> double Statement::get(int offset) {
- assert(stmt);
- return sqlite3_column_double(stmt, offset);
+ assert(impl);
+ return sqlite3_column_double(impl->stmt, offset);
}
template <> std::string Statement::get(int offset) {
- assert(stmt);
+ assert(impl);
return {
- reinterpret_cast<const char *>(sqlite3_column_blob(stmt, offset)),
- size_t(sqlite3_column_bytes(stmt, offset))
+ reinterpret_cast<const char *>(sqlite3_column_blob(impl->stmt, offset)),
+ size_t(sqlite3_column_bytes(impl->stmt, offset))
};
}
template <> std::vector<uint8_t> Statement::get(int offset) {
- assert(stmt);
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, offset));
- const uint8_t* end = begin + sqlite3_column_bytes(stmt, offset);
+ assert(impl);
+ const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
+ const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
return { begin, end };
}
template <>
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
Statement::get(int offset) {
- assert(stmt);
+ assert(impl);
return std::chrono::time_point_cast<std::chrono::seconds>(
- std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt, offset)));
+ std::chrono::system_clock::from_time_t(sqlite3_column_int64(impl->stmt, offset)));
}
template <> optional<int64_t> Statement::get(int offset) {
- assert(stmt);
- if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) {
+ assert(impl);
+ if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
return optional<int64_t>();
} else {
return get<int64_t>(offset);
@@ -321,8 +345,8 @@ template <> optional<int64_t> Statement::get(int offset) {
}
template <> optional<double> Statement::get(int offset) {
- assert(stmt);
- if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) {
+ assert(impl);
+ if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
return optional<double>();
} else {
return get<double>(offset);
@@ -330,8 +354,8 @@ template <> optional<double> Statement::get(int offset) {
}
template <> optional<std::string> Statement::get(int offset) {
- assert(stmt);
- if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) {
+ assert(impl);
+ if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
return optional<std::string>();
} else {
return get<std::string>(offset);
@@ -341,8 +365,8 @@ 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(stmt);
- if (sqlite3_column_type(stmt, offset) == SQLITE_NULL) {
+ assert(impl);
+ if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
return {};
} else {
return get<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>(
@@ -351,13 +375,24 @@ Statement::get(int offset) {
}
void Statement::reset() {
- assert(stmt);
- sqlite3_reset(stmt);
+ assert(impl);
+ sqlite3_reset(impl->stmt);
}
void Statement::clearBindings() {
- assert(stmt);
- sqlite3_clear_bindings(stmt);
+ assert(impl);
+ sqlite3_clear_bindings(impl->stmt);
+}
+
+int64_t Statement::lastInsertRowId() const {
+ assert(impl);
+ return impl->lastInsertRowId;
+}
+
+uint64_t Statement::changes() const {
+ assert(impl);
+ auto changes = impl->changes;
+ return (changes < 0 ? 0 : changes);
}
Transaction::Transaction(Database& db_, Mode mode)
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 8e4a4b971e..2cbc3cf48b 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -4,9 +4,7 @@
#include <vector>
#include <stdexcept>
#include <chrono>
-
-typedef struct sqlite3 sqlite3;
-typedef struct sqlite3_stmt sqlite3_stmt;
+#include <memory>
namespace mapbox {
namespace sqlite {
@@ -22,12 +20,20 @@ enum OpenFlag : int {
};
struct Exception : std::runtime_error {
+ enum Code : int {
+ OK = 0,
+ CANTOPEN = 14,
+ 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 = 0;
+ const int code = OK;
};
+class DatabaseImpl;
class Statement;
+class StatementImpl;
class Database {
private:
@@ -42,16 +48,14 @@ public:
explicit operator bool() const;
- static void errorLogCallback(void *arg, const int err, const char *msg);
void setBusyTimeout(std::chrono::milliseconds);
void exec(const std::string &sql);
Statement prepare(const char *query);
- int64_t lastInsertRowid() const;
- uint64_t changes() const;
-
private:
- sqlite3 *db = nullptr;
+ std::unique_ptr<DatabaseImpl> impl;
+
+ friend class Statement;
};
class Statement {
@@ -59,10 +63,8 @@ private:
Statement(const Statement &) = delete;
Statement &operator=(const Statement &) = delete;
- void check(int err);
-
public:
- Statement(sqlite3 *db, const char *sql);
+ Statement(Database *db, const char *sql);
Statement(Statement &&);
~Statement();
Statement &operator=(Statement &&);
@@ -85,8 +87,11 @@ public:
void reset();
void clearBindings();
+ int64_t lastInsertRowId() const;
+ uint64_t changes() const;
+
private:
- sqlite3_stmt *stmt = nullptr;
+ std::unique_ptr<StatementImpl> impl;
};
class Transaction {
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index fdf82fda8f..4070a0fe9b 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -42,6 +42,8 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
height = videoMode->height;
}
+ glfwWindowHint(GLFW_COCOA_GRAPHICS_SWITCHING, GL_TRUE);
+
#ifdef DEBUG
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
#endif
@@ -107,10 +109,11 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("- Press `7` through `0` to add increasing numbers of shape annotations for testing\n");
printf("\n");
printf("- Press `Q` to remove annotations\n");
- printf("- Press `P` to add a random custom runtime imagery annotation\n");
+ printf("- Press `K` to add a random custom runtime imagery annotation\n");
printf("- Press `L` to add a random line annotation\n");
printf("- Press `W` to pop the last-added annotation off\n");
printf("\n");
+ printf("- Press `P` to pause tile requests\n");
printf("- `Control` + mouse drag to rotate\n");
printf("- `Shift` + mouse drag to tilt\n");
printf("\n");
@@ -198,10 +201,13 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
auto result = view->map->queryPointAnnotations({ {}, { double(view->getSize().width), double(view->getSize().height) } });
printf("visible point annotations: %lu\n", result.size());
} break;
+ case GLFW_KEY_P:
+ view->pauseResumeCallback();
+ break;
case GLFW_KEY_C:
view->clearAnnotations();
break;
- case GLFW_KEY_P:
+ case GLFW_KEY_K:
view->addRandomCustomPointAnnotations(1);
break;
case GLFW_KEY_L:
@@ -384,6 +390,7 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
view->fbWidth = width;
view->fbHeight = height;
+ view->bind();
// This is only triggered when the framebuffer is resized, but not the window. It can
// happen when you move the window between screens with a different pixel ratio.
@@ -410,9 +417,9 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi
double now = glfwGetTime();
if (now - view->lastClick < 0.4 /* ms */) {
if (modifiers & GLFW_MOD_SHIFT) {
- view->map->scaleBy(0.5, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500));
+ view->map->scaleBy(0.5, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
} else {
- view->map->scaleBy(2.0, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500));
+ view->map->scaleBy(2.0, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::AnimationOptions{{mbgl::Milliseconds(500)}});
}
}
view->lastClick = now;
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index 672fa2e13c..a426e58a94 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/gl/gl.hpp>
#include <mbgl/map/map.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/map/backend.hpp>
@@ -26,6 +27,10 @@ public:
// The expected action is to set a new style, different to the current one.
void setChangeStyleCallback(std::function<void()> callback);
+ void setPauseResumeCallback(std::function<void()> callback) {
+ pauseResumeCallback = callback;
+ };
+
void setShouldClose();
void setWindowTitle(const std::string&);
@@ -54,7 +59,7 @@ private:
// Internal
void report(float duration);
-
+
void setMapChangeCallback(std::function<void(mbgl::MapChange)> callback);
void notifyMapChange(mbgl::MapChange change) override;
@@ -103,6 +108,7 @@ private:
double lastClick = -1;
std::function<void()> changeStyleCallback;
+ std::function<void()> pauseResumeCallback;
mbgl::util::RunLoop runLoop;
mbgl::util::Timer frameTick;
diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp
index 1f683b185f..fbfba0b7fb 100644
--- a/platform/glfw/main.cpp
+++ b/platform/glfw/main.cpp
@@ -153,6 +153,18 @@ int main(int argc, char *argv[]) {
mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name);
});
+ view->setPauseResumeCallback([&fileSource] () {
+ static bool isPaused = false;
+
+ if (isPaused) {
+ fileSource.resume();
+ } else {
+ fileSource.pause();
+ }
+
+ isPaused = !isPaused;
+ });
+
// Load style
if (style.empty()) {
const char *url = getenv("MAPBOX_STYLE_URL");
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 9c3b0653c0..32fa6cb4c3 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -8,10 +8,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Added support for right-to-left text and Arabic ligatures in labels. ([#6984](https://github.com/mapbox/mapbox-gl-native/pull/6984), [#7123](https://github.com/mapbox/mapbox-gl-native/pull/7123))
* Improved the line wrapping behavior of point-placed labels, especially labels written in Chinese and Japanese. ([#6828](https://github.com/mapbox/mapbox-gl-native/pull/6828), [#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446))
-* Added a Simplified Chinese localization. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316))
+* CJK characters now remain upright in vertically oriented labels that have line placement, such as road labels. ([#7114](https://github.com/mapbox/mapbox-gl-native/issues/7114))
+* Added Chinese (Simplified and Traditional), French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Russian, Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999))
### Styles
+* Added support for data-driven styling in the form of source and composite style functions. `MGLStyleFunction` is now an abstract class, with `MGLCameraStyleFunction` providing the behavior of `MGLStyleFunction` in previous releases. New `MGLStyleFunction` subclasses allow you to vary a style attribute by the values of attributes of features in the source. ([#7596](https://github.com/mapbox/mapbox-gl-native/pull/7596))
* Added `circleStrokeColor`, `circleStrokeWidth`, and `circleStrokeOpacity` properties to MGLCircleStyleLayer and support for corresponding properties in style JSON files. ([#7356](https://github.com/mapbox/mapbox-gl-native/pull/7356))
* Point-placed labels in symbol style layers are now placed at more optimal locations within polygons. ([#7465](https://github.com/mapbox/mapbox-gl-native/pull/7465))
* Fixed flickering that occurred when manipulating a style layer. ([#7616](https://github.com/mapbox/mapbox-gl-native/pull/7616))
@@ -21,15 +23,52 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed incorrect interpolation of style functions in Boolean-typed style attributes. ([#7526](https://github.com/mapbox/mapbox-gl-native/pull/7526))
* Removed support for the `ref` property in layers in style JSON files. ([#7586](https://github.com/mapbox/mapbox-gl-native/pull/7586))
* Fixed an issue that collapsed consecutive newlines within text labels. ([#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446))
+* Fixed artifacts when drawing particularly acute line joins. ([#7786](https://github.com/mapbox/mapbox-gl-native/pull/7786))
+* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989), [#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971))
+* Fixed an issue causing vector style layer predicates to be evaluated as if each feature had a `$type` attribute of 1, 2, or 3. The `$type` key path can now be compared to `Point`, `LineString`, or `Polygon`, as described in the documentation. ([#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971))
+* When setting an `MGLShapeSource`’s shape to an `MGLFeature` instance, any `UIColor` attribute value is now converted to the equivalent CSS string representation for use with `MGLInterpolationModeIdentity` in style functions. ([#8025](https://github.com/mapbox/mapbox-gl-native/pull/8025))
+* An exception is no longer thrown if layers or sources are removed from a style before they are added. ([#7962](https://github.com/mapbox/mapbox-gl-native/pull/7962))
* Added `MGLComputedShapeSource` source class that allows applications to supply vector data on a per-tile basis.
+### User interaction
+
+* Added a method to MGLMapViewDelegate, `-mapView:shouldChangeFromCamera:toCamera:`, that you can implement to restrict which parts the user can navigate to using gestures. ([#5584](https://github.com/mapbox/mapbox-gl-native/pull/5584))
+* Annotations are no longer deselected when the map is panned or zoomed, even if the annotation moves out of the visible bounds. ([#8022](https://github.com/mapbox/mapbox-gl-native/pull/8022))
+* Double-tap and two-finger tap gestures now zoom to the nearest integer zoom level. ([#8027](https://github.com/mapbox/mapbox-gl-native/pull/8027))
+
+### Networking and offline maps
+
+* Offline pack notifications are now posted by `MGLOfflinePack` instances instead of the shared `MGLOfflineStorage` object. For backwards compatibility, the `userInfo` dictionary still indicates the pack’s state and progress. ([#7952](https://github.com/mapbox/mapbox-gl-native/pull/7952))
+* Fixed a memory leak in MGLMapView. ([#7956](https://github.com/mapbox/mapbox-gl-native/pull/7956))
+* Fixed an issue that could prevent a cached style from appearing while the device is offline. ([#7770](https://github.com/mapbox/mapbox-gl-native/pull/7770))
+* Fixed an issue that could prevent a style from loading when reestablishing a network connection. ([#7902](https://github.com/mapbox/mapbox-gl-native/pull/7902))
+* `MGLOfflineStorage` instances now support a delegate conforming to `MGLOfflineStorageDelegate`, which allows altering URLs before they are requested from the internet. ([#8084](https://github.com/mapbox/mapbox-gl-native/pull/8084))
+
### Other changes
+* The minimum deployment target for this SDK is now iOS 8. ([#8129](https://github.com/mapbox/mapbox-gl-native/pull/8129))
+* Fixed an issue that, among other things, caused various islands to disappear at certain zoom levels. ([#7621](https://github.com/mapbox/mapbox-gl-native/pull/7621))
* Fixed an issue where translucent, non-view-backed point annotations along tile boundaries would be drawn darker than expected. ([#6832](https://github.com/mapbox/mapbox-gl-native/pull/6832))
* Fixed flickering that occurred when panning past the antimeridian. ([#7574](https://github.com/mapbox/mapbox-gl-native/pull/7574))
-* Fixed an issue that could prevent a cached style from appearing while the device is offline. ([#7770](https://github.com/mapbox/mapbox-gl-native/pull/7770))
+* Added a `MGLDistanceFormatter` class for formatting geographic distances. ([#7888](https://github.com/mapbox/mapbox-gl-native/pull/7888))
+* Fixed an issue that was causing the system location indicator to stay on in background after telemetry was disabled. ([#7833](https://github.com/mapbox/mapbox-gl-native/pull/7833))
+
+## 3.4.2 - February 21, 2017
+
+This is the final scheduled version of the Mapbox iOS SDK that supports iOS 7. ([#8129](https://github.com/mapbox/mapbox-gl-native/pull/8129))
+
+* A programmatic change to an MGLMapView’s camera no longer resets the user tracking mode. ([#7856](https://github.com/mapbox/mapbox-gl-native/pull/7856))
+* Improved the performance of trivial camera animations. ([#7125](https://github.com/mapbox/mapbox-gl-native/pull/7125))
+* Added a guide detailing the built-in gesture recognizers and various ways to configure them. ([#7937](https://github.com/mapbox/mapbox-gl-native/pull/7937))
+
+## 3.4.1 - January 25, 2017
+
+* Fixed a build error in the static framework flavor of this SDK caused by a missing header. ([#7844](https://github.com/mapbox/mapbox-gl-native/pull/7844))
+* Fixed an issue causing MGLMapView’s `camera`’s `heading` to be set to a negative value, indicating an undefined heading, when the map view faces northwest. The heading is now wrapped to between zero and 360 degrees, for consistency with MGLMapView’s `direction` property. ([#7724](https://github.com/mapbox/mapbox-gl-native/pull/7724))
+* Fixed an issue where MGLMapView could initially flash black before loading. ([#7859](https://github.com/mapbox/mapbox-gl-native/pull/7859))
+* Deprecated the style class methods in MGLStyle. ([#7785](https://github.com/mapbox/mapbox-gl-native/pull/7785))
-## 3.4.0
+## 3.4.0 - January 20, 2017
### Packaging
@@ -76,7 +115,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
### Annotations
* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
-* Added new APIs to MGLMapView to query for visible annotations. Combined with `-[MGLMapView viewForAnnotation:]`, these APIs can be used to access all visible annotation views. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
+* Added new APIs to MGLMapView to query for visible annotations. Combined with `-[MGLMapView viewForAnnotation:]`, these APIs can be used to access all visible annotation views. ([#6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
* Shape, feature, and annotation classes now conform to NSSecureCoding. ([#6559](https://github.com/mapbox/mapbox-gl-native/pull/6559))
* Fixed an issue causing offscreen annotation views to be updated even when they were in the reuse queue. ([#5987](https://github.com/mapbox/mapbox-gl-native/pull/5987))
* Fixed an issue preventing MGLAnnotationView from animating when its coordinate changes. ([#6215](https://github.com/mapbox/mapbox-gl-native/pull/6215))
@@ -279,7 +318,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
- Heading or course tracking mode can now be enabled as soon as an MGLMapView is initialized. ([#3680](https://github.com/mapbox/mapbox-gl-native/pull/3680))
- Zooming and rotation gestures no longer disable user tracking mode. ([#3589](https://github.com/mapbox/mapbox-gl-native/pull/3589))
- User tracking mode starts out at a lower zoom level by default. ([#3589](https://github.com/mapbox/mapbox-gl-native/pull/3589))
-- Fixed an issue with small map views not properly fitting annotations within bounds. (#[3407](https://github.com/mapbox/mapbox-gl-native/pull/3407))
+- Fixed an issue with small map views not properly fitting annotations within bounds. ([#3407](https://github.com/mapbox/mapbox-gl-native/pull/3407))
- When the user rotates the map to within 7° of true north, the map view now snaps to true north. ([#3403](https://github.com/mapbox/mapbox-gl-native/pull/3403))
- The map view’s background can now be transparent or translucent, as long as the style’s background layer is transparent or translucent and `MGLMapView.opaque` is set to `NO`. ([#3096](https://github.com/mapbox/mapbox-gl-native/pull/3096))
- Documentation is now generated by [jazzy](https://github.com/realm/jazzy) instead of appledoc. ♪♫ ([#3203](https://github.com/mapbox/mapbox-gl-native/pull/3203))
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 72ad84868e..26ab807e04 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -4,7 +4,7 @@ This document explains how to build the Mapbox iOS SDK from source. It is intend
## Requirements
-The Mapbox iOS SDK and iosapp demo application build against the iOS 7.0 SDK. The SDK is intended to run on iOS 7.0 and above, while iosapp is intended to run on iOS 8.0 and above due to the use of a dynamic framework. Both require Xcode on a computer running macOS.
+The Mapbox iOS SDK and iosapp demo application require iOS 8.0 or above.
The Mapbox iOS SDK requires Xcode 7.3 or above. The iosapp demo application requires Xcode 8.0 or above to build.
@@ -52,7 +52,7 @@ You can customize the build output by passing the following arguments into the `
* `BUILDTYPE=Release` will optimize for distribution. Defaults to `Debug`.
* `BUILD_DEVICE=false` builds only for the iOS Simulator.
-* `FORMAT=dynamic` builds only a dynamic framework. `FORMAT=static` builds only a static framework, for compatibility with iOS 7.x.
+* `FORMAT=dynamic` builds only a dynamic framework. `FORMAT=static` builds only a static framework, for legacy compatibility.
* `SYMBOLS=NO` strips the build output of any debug symbols, yielding much smaller binaries. Defaults to `YES`.
An example command that creates a dynamic framework suitable for eventual App Store distribution:
@@ -112,12 +112,25 @@ To add or update text that the user may see in the iOS SDK:
### Adding a localization
-To add a localization to the iOS SDK:
+Translations of all the Mapbox GL Native SDKs are managed [in Transifex](https://www.transifex.com/mapbox/mapbox-gl-native/). If your language already has a translation, feel free to complete or proofread it. Otherwise, please [request your language](https://www.transifex.com/mapbox/mapbox-gl-native/languages/). Note that we’re primarily interested in languages that iOS supports as system languages.
+
+Once you’ve finished translating the SDK into a new language in Transifex, perform these steps to make Xcode aware of the translation:
1. In ios.xcworkspace, open the project editor for ios.xcodeproj. Using the project editor’s sidebar or tab bar dropdown, go to the “ios” project; under the Localizations section of the Info tab, click the + button to add your language to the project.
-1. In the sheet that appears, select all the .strings and .stringsdict files but not the .storyboard file. (LaunchScreen.storyboard is part of the iosapp example application, which is not localized.)
-1. In the Project navigator, expand each .strings and .stringsdict file in the project. An additional version for your localization should be listed; translate it. Translate everything on the right side of the equals sign. Leave the left side and any comments unmodified. See Apple’s documentation on the [.strings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html) and [.stringsdict](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) formats.
-1. You’re already most of the way towards localizing the macOS SDK too – consider [completing that localization](../macos/DEVELOPING.md#adding-a-localization).
+1. In the sheet that appears, select all the .strings and .stringsdict files but not the .storyboard file. (LaunchScreen.storyboard is part of the iosapp example application, which is not localized.) If your language lacks declension and pluralization, as in the case of Chinese, omit the .stringsdict files.
+1. In the Project navigator, expand each .stringsdict file in the project. An additional version for your localization should be listed; translate it. See Apple’s documentation on the [.stringsdict format](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html).
+1. In the Project navigator, select Demo App/Localizable.strings and then, in the File Inspector, check the box for your new localization.
+1. Repeat the steps above in macos.xcworkspace.
+
+The .strings files should still be in the original English – that’s expected. Now you can pull your translations into this repository:
+
+1. _(First time only.)_ Download the [`tx` command line tool](https://docs.transifex.com/client/installing-the-client) and [configure your .transifexrc](https://docs.transifex.com/client/client-configuration).
+1. Run `tx pull -a`.
+1. Convert any added .strings files from UTF-16 encoding to UTF-8 encoding to facilitate diffing and merging. You can convert the file encoding using Xcode’s File inspector or the following command (substituting _MYLANG_ for the locale code):
+
+```
+find platform/{darwin,ios}/resources platform/macos/sdk -path '*/MYLANG.lproj/*.strings' -exec textutil -convert txt -extension strings -inputencoding UTF-16 -encoding UTF-8 {} -output {} \;
+```
### Adding a code example
diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md
index 9453bbd4b7..3d50ab868f 100644
--- a/platform/ios/INSTALL.md
+++ b/platform/ios/INSTALL.md
@@ -4,7 +4,7 @@ This document explains how to build a development version of Mapbox iOS SDK for
### Requirements
-The Mapbox iOS SDK builds against the iOS 7.0 SDK. It is intended to run on iOS 7.0 and above on the following devices and their simulators:
+The Mapbox iOS SDK is intended to run on iOS 8.0 and above on the following devices and their simulators:
* iPhone 4S and above (5, 5c, 5s, 6, 6 Plus)
* iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2)
@@ -36,7 +36,7 @@ There are several ways to install custom builds of the Mapbox iOS SDK:
#### Dynamic framework
-This is the recommended workflow for manually integrating custom builds of the SDK into an application targeting iOS 8 and above:
+This is the recommended workflow for manually integrating custom builds of the SDK into an application:
1. Build from source manually, per above.
@@ -52,7 +52,7 @@ bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework/strip-fra
#### Static framework
-If your application targets iOS 7.x, you’ll need to install the static framework instead:
+You can alternatively install the SDK as a static framework:
1. Build from source manually, per above.
diff --git a/platform/ios/Mapbox-iOS-SDK-static-part.podspec b/platform/ios/Mapbox-iOS-SDK-static-part.podspec
index 9362a5cac9..b2a114f9d2 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 = '7.0'
+ m.ios.deployment_target = '8.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index 1098c5cd10..24ff0f5e43 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 = '3.4.0-beta.7'
+ version = '3.5.0-beta.1'
m.name = 'Mapbox-iOS-SDK-symbols'
m.version = "#{version}-symbols"
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index cf3f3afa61..3509d9a30f 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 = '3.4.0-beta.7'
+ version = '3.5.0-beta.1'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/README.md b/platform/ios/README.md
index 3d4cc3ff2b..af01aed18d 100644
--- a/platform/ios/README.md
+++ b/platform/ios/README.md
@@ -2,7 +2,7 @@
[![Bitrise](https://www.bitrise.io/app/7514e4cf3da2cc57.svg?token=OwqZE5rSBR9MVWNr_lf4sA&branch=master)](https://www.bitrise.io/app/7514e4cf3da2cc57)
-A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.0 and above using Objective-C, Swift, or Interface Builder.
+A library based on [Mapbox GL Native](../../README.md) 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.
This repository is for day-to-day development of the SDK. Building the SDK yourself requires [a number of dependencies and steps](../../INSTALL.md) that are unnecessary for developing production applications. For production applications, please consider installing an official, prebuilt release instead; see the [Mapbox iOS SDK website](https://www.mapbox.com/ios-sdk/) for installation instructions.
diff --git a/platform/ios/app/Base.lproj/Localizable.strings b/platform/ios/app/Base.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/Base.lproj/Localizable.strings
diff --git a/platform/ios/app/MBXAnnotationView.m b/platform/ios/app/MBXAnnotationView.m
index 61f9b1c047..5b8011c55e 100644
--- a/platform/ios/app/MBXAnnotationView.m
+++ b/platform/ios/app/MBXAnnotationView.m
@@ -7,7 +7,7 @@
- (void)layoutSubviews {
[super layoutSubviews];
-
+
self.layer.borderColor = [UIColor blueColor].CGColor;
self.layer.borderWidth = 1;
self.layer.cornerRadius = 2;
@@ -16,7 +16,7 @@
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
-
+
self.layer.borderColor = selected ? [UIColor blackColor].CGColor : [UIColor whiteColor].CGColor;
self.layer.borderWidth = selected ? 2.0 : 0;
}
@@ -24,7 +24,7 @@
- (void)setDragState:(MGLAnnotationViewDragState)dragState animated:(BOOL)animated
{
[super setDragState:dragState animated:NO];
-
+
switch (dragState) {
case MGLAnnotationViewDragStateNone:
break;
@@ -46,7 +46,7 @@
break;
}
}
-
+
}
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
diff --git a/platform/ios/app/MBXCustomCalloutView.m b/platform/ios/app/MBXCustomCalloutView.m
index e46b727d84..13564c5cbf 100644
--- a/platform/ios/app/MBXCustomCalloutView.m
+++ b/platform/ios/app/MBXCustomCalloutView.m
@@ -31,7 +31,7 @@ static CGFloat const tipWidth = 10.0;
self.backgroundColor = [UIColor clearColor];
_mainLabel = [[UILabel alloc] initWithFrame: CGRectZero];
_mainLabel.backgroundColor = [UIColor clearColor];
-
+
[self addSubview: _mainLabel];
}
return self;
@@ -46,7 +46,7 @@ static CGFloat const tipWidth = 10.0;
{
[self.delegate performSelector:@selector(calloutViewWillAppear:) withObject:self];
}
-
+
[view addSubview:self];
// prepare title label
if ([self.representedObject respondsToSelector:@selector(title)])
@@ -61,7 +61,7 @@ static CGFloat const tipWidth = 10.0;
CGFloat frameOriginY = rect.origin.y - frameHeight;
self.frame = CGRectMake(frameOriginX, frameOriginY,
frameWidth, frameHeight);
-
+
if ([self.delegate respondsToSelector:@selector(calloutViewDidAppear:)])
{
[self.delegate performSelector:@selector(calloutViewDidAppear:) withObject:self];
@@ -84,14 +84,14 @@ static CGFloat const tipWidth = 10.0;
- (void)drawRect:(CGRect)rect
{
UIColor *fillColor = [UIColor colorWithWhite:0.7 alpha:1.0];
-
+
CGFloat tipLeft = rect.origin.x + (rect.size.width / 2.0) - (tipWidth / 2.0);
CGPoint tipBottom = CGPointMake(rect.origin.x + (rect.size.width / 2.0), rect.origin.y +rect.size.height);
CGFloat heightWithoutTip = rect.size.height - tipHeight;
-
+
// draw the white background with tip
CGContextRef ctxt = UIGraphicsGetCurrentContext();
-
+
CGMutablePathRef tipPath = CGPathCreateMutable();
CGPathMoveToPoint(tipPath, NULL, 0, 0);
CGPathAddLineToPoint(tipPath, NULL, 0, heightWithoutTip);
@@ -101,7 +101,7 @@ static CGFloat const tipWidth = 10.0;
CGPathAddLineToPoint(tipPath, NULL, CGRectGetWidth(rect), heightWithoutTip);
CGPathAddLineToPoint(tipPath, NULL, CGRectGetWidth(rect), 0);
CGPathCloseSubpath(tipPath);
-
+
[fillColor setFill];
CGContextAddPath(ctxt, tipPath);
CGContextFillPath(ctxt);
diff --git a/platform/ios/app/MBXOfflinePacksTableViewController.m b/platform/ios/app/MBXOfflinePacksTableViewController.m
index 7bceec7ef7..26a15a0b95 100644
--- a/platform/ios/app/MBXOfflinePacksTableViewController.m
+++ b/platform/ios/app/MBXOfflinePacksTableViewController.m
@@ -33,7 +33,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)viewDidLoad {
[super viewDidLoad];
-
+
[[MGLOfflineStorage sharedOfflineStorage] addObserver:self forKeyPath:@"packs" options:NSKeyValueObservingOptionInitial context:NULL];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackProgressDidChange:) name:MGLOfflinePackProgressChangedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackErrorNotification object:nil];
@@ -60,24 +60,24 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
case NSKeyValueChangeInsertion:
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
break;
-
+
case NSKeyValueChangeRemoval:
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
break;
-
+
case NSKeyValueChangeReplacement:
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
break;
-
+
default:
[self.tableView reloadData];
-
+
for (MGLOfflinePack *pack in [MGLOfflineStorage sharedOfflineStorage].packs) {
if (pack.state == MGLOfflinePackStateUnknown) {
[pack requestProgress];
}
}
-
+
break;
}
} else {
@@ -91,22 +91,22 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
textField.placeholder = [NSString stringWithFormat:@"%@", MGLStringFromCoordinateBounds(self.mapView.visibleCoordinateBounds)];
}];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
-
+
UIAlertAction *downloadAction = [UIAlertAction actionWithTitle:@"Download" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
MGLMapView *mapView = self.mapView;
NSAssert(mapView, @"No map view to get the current region from.");
-
+
UITextField *nameField = alertController.textFields.firstObject;
NSString *name = nameField.text;
if (!name.length) {
name = nameField.placeholder;
}
-
+
MGLTilePyramidOfflineRegion *region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:mapView.styleURL bounds:mapView.visibleCoordinateBounds fromZoomLevel:mapView.zoomLevel toZoomLevel:mapView.maximumZoomLevel];
NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{
MBXOfflinePackContextNameKey: name,
}];
-
+
[[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack *pack, NSError *error) {
if (error) {
NSString *message = [NSString stringWithFormat:@"Mapbox GL was unable to add the offline pack “%@”.", name];
@@ -122,7 +122,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
alertController.preferredAction = downloadAction;
}
-
+
[self presentViewController:alertController animated:YES completion:nil];
}
@@ -134,11 +134,11 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs[indexPath.row];
-
+
NSString *reuseIdentifier = pack.state == MGLOfflinePackStateActive ? MBXOfflinePacksTableViewActiveCellReuseIdentifier : MBXOfflinePacksTableViewInactiveCellReuseIdentifier;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
[self updateTableViewCell:cell atIndexPath:indexPath forPack:pack];
-
+
return cell;
}
@@ -156,17 +156,17 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
case MGLOfflinePackStateUnknown:
statusString = @"Calculating progress…";
break;
-
+
case MGLOfflinePackStateInactive:
statusString = [NSString stringWithFormat:@"%@ of %@ resources (%@)",
completedString, expectedString, byteCountString];
break;
-
+
case MGLOfflinePackStateComplete:
statusString = [NSString stringWithFormat:@"%@ resources (%@)",
completedString, byteCountString];
break;
-
+
case MGLOfflinePackStateActive:
if (progress.countOfResourcesExpected) {
completedString = [NSNumberFormatter localizedStringFromNumber:@(progress.countOfResourcesCompleted + 1)
@@ -178,7 +178,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
statusString = [NSString stringWithFormat:@"Downloading %@ of %@ resources (%@ so far)…",
completedString, expectedString, byteCountString];
break;
-
+
case MGLOfflinePackStateInvalid:
NSAssert(NO, @"Invalid offline pack at index path %@", indexPath);
break;
@@ -197,27 +197,27 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
-
+
MGLOfflinePack *pack = [MGLOfflineStorage sharedOfflineStorage].packs[indexPath.row];
switch (pack.state) {
case MGLOfflinePackStateUnknown:
break;
-
+
case MGLOfflinePackStateComplete:
if ([pack.region respondsToSelector:@selector(applyToMapView:)]) {
[pack.region performSelector:@selector(applyToMapView:) withObject:self.mapView];
}
[self performSegueWithIdentifier:@"ReturnToMap" sender:self];
break;
-
+
case MGLOfflinePackStateInactive:
[pack resume];
break;
-
+
case MGLOfflinePackStateActive:
[pack suspend];
break;
-
+
case MGLOfflinePackStateInvalid:
NSAssert(NO, @"Invalid offline pack at index path %@", indexPath);
break;
@@ -229,12 +229,12 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)offlinePackProgressDidChange:(NSNotification *)notification {
MGLOfflinePack *pack = notification.object;
NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
-
+
NSUInteger index = [[MGLOfflineStorage sharedOfflineStorage].packs indexOfObject:pack];
if (index == NSNotFound) {
return;
}
-
+
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
[self updateTableViewCell:cell atIndexPath:indexPath forPack:pack];
@@ -243,10 +243,10 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)offlinePackDidReceiveError:(NSNotification *)notification {
MGLOfflinePack *pack = notification.object;
NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
-
+
NSError *error = notification.userInfo[MGLOfflinePackUserInfoKeyError];
NSAssert([error isKindOfClass:[NSError class]], @"MGLOfflineStorage notification has a non-error error.");
-
+
NSString *message = [NSString stringWithFormat:@"Mapbox GL encountered an error while downloading the offline pack “%@”: %@", pack.name, error.localizedFailureReason];
if (error.code == MGLErrorCodeConnectionFailed) {
NSLog(@"%@", message);
@@ -260,7 +260,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
- (void)offlinePackDidReceiveMaximumAllowedMapboxTiles:(NSNotification *)notification {
MGLOfflinePack *pack = notification.object;
NSAssert([pack isKindOfClass:[MGLOfflinePack class]], @"MGLOfflineStorage notification has a non-pack object.");
-
+
uint64_t maximumCount = [notification.userInfo[MGLOfflinePackUserInfoKeyMaximumCount] unsignedLongLongValue];
NSLog(@"Offline pack “%@” reached limit of %llu tiles.", pack.name, maximumCount);
}
diff --git a/platform/ios/app/MBXUserLocationAnnotationView.m b/platform/ios/app/MBXUserLocationAnnotationView.m
index a0347a174f..675a01930a 100644
--- a/platform/ios/app/MBXUserLocationAnnotationView.m
+++ b/platform/ios/app/MBXUserLocationAnnotationView.m
@@ -35,7 +35,7 @@ const CGFloat MBXUserLocationDotSize = 10;
- (void)updateFrameWithSize:(CGSize)size
{
if (CGSizeEqualToSize(self.frame.size, size)) return;
-
+
// Update frame size, keeping the existing center point.
CGRect newFrame = self.frame;
CGPoint oldCenter = self.center;
@@ -59,23 +59,23 @@ const CGFloat MBXUserLocationDotSize = 10;
{
// Accuracy
CGFloat accuracy = self.accuracyInPoints;
-
+
CGFloat center = self.bounds.size.width / 2.0 - accuracy / 2.0;
UIBezierPath *accuracyPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(center, center, accuracy, accuracy)];
UIColor *accuracyColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:.4];
[accuracyColor setFill];
[accuracyPath fill];
-
+
// Dot
center = self.bounds.size.width / 2.0 - MBXUserLocationDotSize / 2.0;
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(center, center, MBXUserLocationDotSize, MBXUserLocationDotSize)];
[UIColor.greenColor setFill];
[ovalPath fill];
-
+
[UIColor.blackColor setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
-
+
// Accuracy text
UIFont *font = [UIFont systemFontOfSize:11];
[[NSString stringWithFormat:@"%.0f", accuracy]
@@ -89,7 +89,7 @@ const CGFloat MBXUserLocationDotSize = 10;
UIColor* fillColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];
UIColor* strokeColor = [UIColor colorWithRed: 0.592 green: 0.592 blue: 0.592 alpha: 1];
UIColor* fillColor2 = [UIColor colorWithRed: 1 green: 1 blue: 1 alpha: 1];
-
+
UIBezierPath* bezier2Path = [UIBezierPath bezierPath];
[bezier2Path moveToPoint: CGPointMake(30, 7.86)];
[bezier2Path addLineToPoint: CGPointMake(30, 52.66)];
@@ -98,10 +98,10 @@ const CGFloat MBXUserLocationDotSize = 10;
[bezier2Path addCurveToPoint: CGPointMake(30, 7.86) controlPoint1: CGPointMake(-0, -2.17) controlPoint2: CGPointMake(30, -3.05)];
[bezier2Path closePath];
bezier2Path.usesEvenOddFillRule = YES;
-
+
[fillColor setFill];
[bezier2Path fill];
-
+
UIBezierPath* bezier3Path = [UIBezierPath bezierPath];
[bezier3Path moveToPoint: CGPointMake(30, 7.86)];
[bezier3Path addLineToPoint: CGPointMake(30, 52.66)];
@@ -112,7 +112,7 @@ const CGFloat MBXUserLocationDotSize = 10;
[strokeColor setStroke];
bezier3Path.lineWidth = 1;
[bezier3Path stroke];
-
+
UIBezierPath* bezier4Path = [UIBezierPath bezierPath];
[bezier4Path moveToPoint: CGPointMake(15.56, 4.26)];
[bezier4Path addCurveToPoint: CGPointMake(26, 6) controlPoint1: CGPointMake(21, 4.26) controlPoint2: CGPointMake(26, 6)];
@@ -123,10 +123,10 @@ const CGFloat MBXUserLocationDotSize = 10;
[bezier4Path addCurveToPoint: CGPointMake(15.56, 4.26) controlPoint1: CGPointMake(4, 6) controlPoint2: CGPointMake(10.12, 4.26)];
[bezier4Path closePath];
bezier4Path.usesEvenOddFillRule = YES;
-
+
[fillColor2 setFill];
[bezier4Path fill];
-
+
UIBezierPath* rectanglePath = [UIBezierPath bezierPath];
[rectanglePath moveToPoint: CGPointMake(25, 46)];
[rectanglePath addCurveToPoint: CGPointMake(21, 55) controlPoint1: CGPointMake(31, 46) controlPoint2: CGPointMake(28.5, 55)];
@@ -136,11 +136,11 @@ const CGFloat MBXUserLocationDotSize = 10;
[rectanglePath closePath];
[UIColor.whiteColor setFill];
[rectanglePath fill];
-
+
UIBezierPath* bezierPath = [UIBezierPath bezierPath];
[UIColor.whiteColor setFill];
[bezierPath fill];
-
+
UIBezierPath* rectangle2Path = [UIBezierPath bezierPath];
[rectangle2Path moveToPoint: CGPointMake(2, 35)];
[rectangle2Path addCurveToPoint: CGPointMake(4.36, 35) controlPoint1: CGPointMake(2, 39) controlPoint2: CGPointMake(4.36, 35)];
@@ -150,7 +150,7 @@ const CGFloat MBXUserLocationDotSize = 10;
[rectangle2Path closePath];
[UIColor.whiteColor setFill];
[rectangle2Path fill];
-
+
UIBezierPath* rectangle3Path = [UIBezierPath bezierPath];
[rectangle3Path moveToPoint: CGPointMake(28, 35)];
[rectangle3Path addCurveToPoint: CGPointMake(25.64, 35) controlPoint1: CGPointMake(28, 39) controlPoint2: CGPointMake(25.64, 35)];
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 9b0d72f177..6a07115af1 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -6,8 +6,6 @@
#import "MBXAnnotationView.h"
#import "MBXUserLocationAnnotationView.h"
-#import "MGLFillStyleLayer.h"
-
#import <Mapbox/Mapbox.h>
#import <objc/runtime.h>
@@ -35,6 +33,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsCoreRenderingRows) {
MBXSettingsCoreRenderingTimestamps,
MBXSettingsCoreRenderingCollisionBoxes,
MBXSettingsCoreRenderingOverdrawVisualization,
+ MBXSettingsCoreRenderingToggleTwoMaps,
};
typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) {
@@ -72,6 +71,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) {
MBXSettingsRuntimeStylingRasterSource,
MBXSettingsRuntimeStylingCountryLabels,
MBXSettingsRuntimeStylingRouteLine,
+ MBXSettingsRuntimeStylingDDSPolygon,
MBXSettingsRuntimeStylingCustomLatLonGrid,
};
@@ -79,6 +79,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MBXSettingsMiscellaneousShowReuseQueueStats = 0,
MBXSettingsMiscellaneousWorldTour,
MBXSettingsMiscellaneousCustomUserDot,
+ MBXSettingsMiscellaneousShowZoomLevel,
MBXSettingsMiscellaneousPrintLogFile,
MBXSettingsMiscellaneousDeleteLogFile,
};
@@ -116,6 +117,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@property (nonatomic) BOOL customUserLocationAnnnotationEnabled;
@property (nonatomic) BOOL usingLocaleBasedCountryLabels;
@property (nonatomic) BOOL reuseQueueStatsEnabled;
+@property (nonatomic) BOOL showZoomLevelEnabled;
@end
@@ -148,7 +150,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)viewDidLoad
{
[super viewDidLoad];
-
+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(restoreState:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveState:) name:UIApplicationWillTerminateNotification object:nil];
@@ -156,6 +158,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self restoreState:nil];
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
+
self.hudLabel.hidden = YES;
if ([MGLAccountManager accessToken].length)
@@ -172,7 +175,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
}];
-
+
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
UIAlertAction *OKAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action)
{
@@ -180,13 +183,13 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
NSString *accessToken = textField.text;
[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:MBXMapboxAccessTokenDefaultsKey];
[MGLAccountManager setAccessToken:accessToken];
-
+
self.styleIndex = -1;
[self cycleStyles:self];
[self.mapView reloadStyle:self];
}];
[alertController addAction:OKAction];
-
+
if ([alertController respondsToSelector:@selector(setPreferredAction:)])
{
alertController.preferredAction = OKAction;
@@ -299,6 +302,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
(debugMask & MGLMapDebugCollisionBoxesMask ? @"Hide" :@"Show")],
[NSString stringWithFormat:@"%@ Overdraw Visualization",
(debugMask & MGLMapDebugOverdrawVisualizationMask ? @"Hide" :@"Show")],
+ [NSString stringWithFormat:@"%@ Second Map",
+ ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")],
]];
break;
case MBXSettingsAnnotations:
@@ -338,15 +343,16 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Style Raster Source",
[NSString stringWithFormat:@"Label Countries in %@", (_usingLocaleBasedCountryLabels ? @"Local Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@"Add Route Line",
+ @"Dynamically Style Polygon",
@"Add Custom Lat/Lon Grid",
]];
break;
case MBXSettingsMiscellaneous:
- [settingsTitles addObject:@"Show Reuse Queue Stats"];
-
[settingsTitles addObjectsFromArray:@[
+ [NSString stringWithFormat:@"%@ Reuse Queue Stats", (_reuseQueueStatsEnabled ? @"Hide" :@"Show")],
@"Start World Tour",
[NSString stringWithFormat:@"%@ Custom User Dot", (_customUserLocationAnnnotationEnabled ? @"Disable" : @"Enable")],
+ [NSString stringWithFormat:@"%@ Zoom Level", (_showZoomLevelEnabled ? @"Hide" :@"Show")],
]];
if (self.debugLoggingEnabled)
@@ -391,6 +397,81 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsCoreRenderingOverdrawVisualization:
self.mapView.debugMask ^= MGLMapDebugOverdrawVisualizationMask;
break;
+ case MBXSettingsCoreRenderingToggleTwoMaps:
+ if ([self.view viewWithTag:2] == nil) {
+ MGLMapView *secondMapView = [[MGLMapView alloc] initWithFrame:
+ CGRectMake(0, self.view.bounds.size.height / 2,
+ self.view.bounds.size.width, self.view.bounds.size.height / 2)];
+ secondMapView.translatesAutoresizingMaskIntoConstraints = false;
+ secondMapView.tag = 2;
+ for (NSLayoutConstraint *constraint in self.view.constraints)
+ {
+ if ((constraint.firstItem == self.mapView && constraint.firstAttribute == NSLayoutAttributeBottom) ||
+ (constraint.secondItem == self.mapView && constraint.secondAttribute == NSLayoutAttributeBottom))
+ {
+ [self.view removeConstraint:constraint];
+ break;
+ }
+ }
+ [self.view addSubview:secondMapView];
+ [self.view addConstraints:@[
+ [NSLayoutConstraint constraintWithItem:self.mapView
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeCenterY
+ multiplier:1
+ constant:0],
+ [NSLayoutConstraint constraintWithItem:secondMapView
+ attribute:NSLayoutAttributeCenterX
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeCenterX
+ multiplier:1
+ constant:0],
+ [NSLayoutConstraint constraintWithItem:secondMapView
+ attribute:NSLayoutAttributeWidth
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeWidth
+ multiplier:1
+ constant:0],
+ [NSLayoutConstraint constraintWithItem:secondMapView
+ attribute:NSLayoutAttributeTop
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.view
+ attribute:NSLayoutAttributeCenterY
+ multiplier:1
+ constant:0],
+ [NSLayoutConstraint constraintWithItem:secondMapView
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.bottomLayoutGuide
+ attribute:NSLayoutAttributeTop
+ multiplier:1
+ constant:0],
+ ]];
+ } else {
+ NSMutableArray *constraintsToRemove = [NSMutableArray array];
+ MGLMapView *secondMapView = (MGLMapView *)[self.view viewWithTag:2];
+ for (NSLayoutConstraint *constraint in self.view.constraints)
+ {
+ if (constraint.firstItem == secondMapView || constraint.secondItem == secondMapView)
+ {
+ [constraintsToRemove addObject:constraint];
+ }
+ }
+ [self.view removeConstraints:constraintsToRemove];
+ [secondMapView removeFromSuperview];
+ [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.mapView
+ attribute:NSLayoutAttributeBottom
+ relatedBy:NSLayoutRelationEqual
+ toItem:self.bottomLayoutGuide
+ attribute:NSLayoutAttributeTop
+ multiplier:1
+ constant:0]];
+ }
+ break;
default:
NSAssert(NO, @"All core rendering setting rows should be implemented");
break;
@@ -500,6 +581,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsRuntimeStylingRouteLine:
[self styleRouteLine];
break;
+ case MBXSettingsRuntimeStylingDDSPolygon:
+ [self stylePolygonWithDDS];
case MBXSettingsRuntimeStylingCustomLatLonGrid:
[self addLatLonGrid];
break;
@@ -525,8 +608,16 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
break;
case MBXSettingsMiscellaneousShowReuseQueueStats:
{
- self.reuseQueueStatsEnabled = YES;
- self.hudLabel.hidden = NO;
+ self.reuseQueueStatsEnabled = !self.reuseQueueStatsEnabled;
+ self.hudLabel.hidden = !self.reuseQueueStatsEnabled;
+ self.showZoomLevelEnabled = NO;
+ break;
+ }
+ case MBXSettingsMiscellaneousShowZoomLevel:
+ {
+ self.showZoomLevelEnabled = !self.showZoomLevelEnabled;
+ self.hudLabel.hidden = !self.showZoomLevelEnabled;
+ self.reuseQueueStatsEnabled = NO;
break;
}
default:
@@ -723,7 +814,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
firstAnnotation.title = @"Open anchored to annotation";
firstAnnotation.anchoredToAnnotation = YES;
firstAnnotation.dismissesAutomatically = NO;
-
+
MBXCustomCalloutAnnotation *secondAnnotation = [[MBXCustomCalloutAnnotation alloc] init];
secondAnnotation.coordinate = CLLocationCoordinate2DMake(48.8543940, 2.3775439);
secondAnnotation.title = @"Open not anchored to annotation";
@@ -735,32 +826,34 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
thirdAnnotation.title = @"Dismisses automatically";
thirdAnnotation.anchoredToAnnotation = YES;
thirdAnnotation.dismissesAutomatically = YES;
-
+
NSArray *annotations = @[firstAnnotation, secondAnnotation, thirdAnnotation];
[self.mapView addAnnotations:annotations];
-
+
[self.mapView showAnnotations:annotations animated:YES];
}
- (void)styleWaterLayer
{
MGLFillStyleLayer *waterLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"];
- MGLStyleValue *waterColorFunction = [MGLStyleValue<UIColor *> valueWithStops:@{
- @6.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor yellowColor]],
- @8.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blueColor]],
- @10.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor redColor]],
- @12.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor greenColor]],
- @14.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blueColor]],
- }];
+ NSDictionary *waterColorStops = @{@6.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor yellowColor]],
+ @8.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blueColor]],
+ @10.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor redColor]],
+ @12.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor greenColor]],
+ @14.0f: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blueColor]]};
+ MGLStyleValue *waterColorFunction = [MGLStyleValue<UIColor *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:waterColorStops
+ options: nil];
waterLayer.fillColor = waterColorFunction;
- MGLStyleValue *fillAntialiasedFunction = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @11: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- @12: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
- @13: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- @14: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
- @15: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
- }];
+ NSDictionary *fillAntialiasedStops = @{@11: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
+ @12: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
+ @13: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES],
+ @14: [MGLStyleValue<NSNumber *> valueWithRawValue:@NO],
+ @15: [MGLStyleValue<NSNumber *> valueWithRawValue:@YES]};
+ MGLStyleValue *fillAntialiasedFunction = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval
+ cameraStops:fillAntialiasedStops
+ options:nil];
waterLayer.fillAntialiased = fillAntialiasedFunction;
}
@@ -769,21 +862,23 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MGLLineStyleLayer *roadLayer = (MGLLineStyleLayer *)[self.mapView.style layerWithIdentifier:@"road-primary"];
roadLayer.lineColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blackColor]];
- MGLStyleValue *lineWidthFunction = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @5: [MGLStyleValue<NSNumber *> valueWithRawValue:@5],
- @10: [MGLStyleValue<NSNumber *> valueWithRawValue:@15],
- @15: [MGLStyleValue<NSNumber *> valueWithRawValue:@30],
- }];
-
- MGLStyleValue *roadLineColor = [MGLStyleValue<UIColor *> valueWithStops:@{
- @10: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor purpleColor]],
- @13: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor yellowColor]],
- @16: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor cyanColor]],
- }];
- roadLayer.lineColor = roadLineColor;
+ NSDictionary *lineWidthStops = @{@5: [MGLStyleValue<NSNumber *> valueWithRawValue:@5],
+ @10: [MGLStyleValue<NSNumber *> valueWithRawValue:@15],
+ @15: [MGLStyleValue<NSNumber *> valueWithRawValue:@30]};
+ MGLStyleValue *lineWidthFunction = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:lineWidthStops
+ options:nil];
roadLayer.lineWidth = lineWidthFunction;
roadLayer.lineGapWidth = lineWidthFunction;
+ NSDictionary *roadLineColorStops = @{@10: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor purpleColor]],
+ @13: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor yellowColor]],
+ @16: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor cyanColor]]};
+ MGLStyleValue *roadLineColor = [MGLStyleValue<UIColor *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:roadLineColorStops
+ options: nil];
+ roadLayer.lineColor = roadLineColor;
+
roadLayer.visible = YES;
roadLayer.maximumZoomLevel = 15;
roadLayer.minimumZoomLevel = 13;
@@ -796,10 +891,10 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView.style addSource:rasterSource];
MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"my-raster-layer" source:rasterSource];
- MGLStyleValue *opacityFunction = [MGLStyleValue<NSNumber *> valueWithStops:@{
- @20.0f: [MGLStyleValue<NSNumber *> valueWithRawValue:@1.0f],
- @5.0f: [MGLStyleValue<NSNumber *> valueWithRawValue:@0.0f],
- }];
+ MGLStyleValue *opacityFunction = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential
+ cameraStops:@{@20.0f: [MGLStyleValue<NSNumber *> valueWithRawValue:@1.0f],
+ @5.0f: [MGLStyleValue<NSNumber *> valueWithRawValue:@0.0f]}
+ options:nil];
rasterLayer.rasterOpacity = opacityFunction;
[self.mapView.style addLayer:rasterLayer];
}
@@ -814,7 +909,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"test" source:source];
fillLayer.fillColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor purpleColor]];
[self.mapView.style addLayer:fillLayer];
-
+
}
- (void)styleSymbolLayer
@@ -828,7 +923,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.mapView.style.transitionDuration = 5;
self.mapView.style.transitionDelay = 1;
MGLFillStyleLayer *buildingLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"building"];
- buildingLayer.fillColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blackColor]];
+ buildingLayer.fillColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor purpleColor]];
}
- (void)styleFerryLayer
@@ -863,18 +958,6 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
});
}
-+ (MGLStyleConstantValue<NSValue *> *)testEnum:(NSUInteger)value type:(const char *)type
-{
- return [MGLStyleConstantValue<NSValue *> valueWithRawValue:[NSValue value:&value withObjCType:type]];
-}
-
-+ (MGLStyleFunction<NSValue *> *)testEnumFunction:(NSUInteger)value type:(const char *)type
-{
- return [MGLStyleFunction<NSValue *> valueWithStops:@{
- @18: [self testEnum:value type:type],
- }];
-}
-
- (void)styleFilteredLines
{
// set style and focus on lower 48
@@ -920,27 +1003,27 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
CGRect queryRect = CGRectInset(self.mapView.bounds, 100, 200);
NSArray *visibleFeatures = [self.mapView visibleFeaturesInRect:queryRect];
-
+
NSString *querySourceID = @"query-source-id";
NSString *queryLayerID = @"query-layer-id";
-
+
// RTE if you don't remove the layer first
// RTE if you pass a nill layer to remove layer
MGLStyleLayer *layer = [self.mapView.style layerWithIdentifier:queryLayerID];
if (layer) {
[self.mapView.style removeLayer:layer];
}
-
+
// RTE if you pass a nill source to remove source
MGLSource *source = [self.mapView.style sourceWithIdentifier:querySourceID];
if (source) {
[self.mapView.style removeSource:source];
}
-
+
dispatch_async(dispatch_get_main_queue(), ^{
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:querySourceID features:visibleFeatures options:nil];
[self.mapView.style addSource:source];
-
+
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:queryLayerID source:source];
fillLayer.fillColor = [MGLStyleConstantValue<UIColor *> valueWithRawValue:[UIColor blueColor]];
fillLayer.fillOpacity = [MGLStyleConstantValue<NSNumber *> valueWithRawValue:@0.5];
@@ -952,7 +1035,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
self.mapView.zoomLevel = 10;
self.mapView.centerCoordinate = CLLocationCoordinate2DMake(51.068585180672635, -114.06074523925781);
-
+
CLLocationCoordinate2D leafCoords[] = {
{50.9683733218221,-114.07035827636719},
{51.02325750523972,-114.06967163085938},
@@ -986,14 +1069,14 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{50.9683733218221,-114.07035827636719},
};
NSUInteger coordsCount = sizeof(leafCoords) / sizeof(leafCoords[0]);
-
+
MGLPolygonFeature *feature = [MGLPolygonFeature polygonWithCoordinates:leafCoords count:coordsCount];
feature.identifier = @"leaf-feature";
feature.attributes = @{@"color": @"red"};
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"leaf-source" shape:feature options:nil];
[self.mapView.style addSource:source];
-
+
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"leaf-fill-layer" source:source];
layer.predicate = [NSPredicate predicateWithFormat:@"color = 'red'"];
MGLStyleValue *fillColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor redColor]];
@@ -1032,17 +1115,17 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)updateShapeSourceData
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(40.329795743702064, -107.75390625) zoomLevel:11 animated:NO];
-
+
NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-104.34814453125,37.64903402157866]]}}]}";
-
+
NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding];
MGLShape *shape = [MGLShape shapeWithData:data encoding:NSUTF8StringEncoding error:NULL];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"mutable-data-source-id" shape:shape options:nil];
[self.mapView.style addSource:source];
-
+
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-id" source:source];
[self.mapView.style addLayer:layer];
-
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSString *geoJSON = @"{\"type\": \"FeatureCollection\",\"features\": [{\"type\": \"Feature\",\"properties\": {},\"geometry\": {\"type\": \"LineString\",\"coordinates\": [[-107.75390625,40.329795743702064],[-109.34814453125,37.64903402157866]]}}]}";
NSData *data = [geoJSON dataUsingEncoding:NSUTF8StringEncoding];
@@ -1054,21 +1137,21 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)updateShapeSourceURL
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(48.668731, -122.857151) zoomLevel:11 animated:NO];
-
+
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"polyline" ofType:@"geojson"];
NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"mutable-data-source-url-id" URL:geoJSONURL options:nil];
[self.mapView.style addSource:source];
-
+
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-url-id" source:source];
[self.mapView.style addLayer:layer];
-
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(41.563986787078704, -75.04843935793578) zoomLevel:8 animated:NO];
-
+
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"threestates" ofType:@"geojson"];
NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath];
-
+
source.URL = geoJSONURL;
});
}
@@ -1076,7 +1159,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)updateShapeSourceFeatures
{
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(-41.1520, 288.6592) zoomLevel:10 animated:NO];
-
+
CLLocationCoordinate2D smallBox[] = {
{-41.14763798539186, 288.68019104003906},
{-41.140915920129665, 288.68019104003906},
@@ -1084,7 +1167,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{-41.14763798539186, 288.6887741088867},
{-41.14763798539186, 288.68019104003906}
};
-
+
CLLocationCoordinate2D largeBox[] = {
{-41.17710352162799, 288.67298126220703},
{-41.13962313627545, 288.67298126220703},
@@ -1092,7 +1175,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{-41.17710352162799, 288.7261962890625},
{-41.17710352162799, 288.67298126220703}
};
-
+
MGLPolygonFeature *smallBoxFeature = [MGLPolygonFeature polygonWithCoordinates:smallBox count:sizeof(smallBox)/sizeof(smallBox[0])];
MGLPolygonFeature *largeBoxFeature = [MGLPolygonFeature polygonWithCoordinates:largeBox count:sizeof(largeBox)/sizeof(largeBox[0])];
@@ -1100,12 +1183,12 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
shape:smallBoxFeature
options:nil];
[self.mapView.style addSource:source];
-
+
MGLFillStyleLayer *layer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"mutable-data-layer-features-id" source:source];
MGLStyleValue *fillColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor redColor]];
layer.fillColor = fillColor;
[self.mapView.style addLayer:layer];
-
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
source.shape = largeBoxFeature;
});
@@ -1123,7 +1206,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MGLPointCollectionFeature *feature = [MGLPointCollectionFeature pointCollectionWithCoordinates:coordinates count:4];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"wiggle-source" shape:feature options:nil];
[self.mapView.style addSource:source];
-
+
MGLCircleStyleLayer *layer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"wiggle-layer" source:source];
[self.mapView.style addLayer:layer];
}
@@ -1133,11 +1216,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
NSURL *url = [[NSURL alloc] initWithString:@"mapbox://mapbox.mapbox-terrain-v2"];
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"style-vector-source-id" configurationURL:url];
[self.mapView.style addSource:vectorSource];
-
+
MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"style-vector-background-layer-id"];
backgroundLayer.backgroundColor = [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor blackColor]];
[self.mapView.style addLayer:backgroundLayer];
-
+
MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"style-vector-line-layer-id" source:vectorSource];
lineLayer.sourceLayerIdentifier = @"contour";
NSUInteger lineJoinValue = MGLLineJoinRound;
@@ -1157,7 +1240,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
MGLTileSourceOptionTileSize: @256,
}];
[self.mapView.style addSource:rasterSource];
-
+
MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"style-raster-layer-id" source:rasterSource];
[self.mapView.style addLayer:rasterLayer];
}
@@ -1210,6 +1293,48 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView.style addLayer:routeLayer];
}
+- (void)stylePolygonWithDDS {
+ CLLocationCoordinate2D leftCoords[] = {
+ {37.73081027834234, -122.49412536621094},
+ {37.7566013348511, -122.49412536621094},
+ {37.7566013348511, -122.46253967285156},
+ {37.73081027834234, -122.46253967285156},
+ {37.73081027834234, -122.49412536621094},
+ };
+ CLLocationCoordinate2D rightCoords[] = {
+ {37.73135334055843, -122.44640350341795},
+ {37.75741564287944, -122.44640350341795},
+ {37.75741564287944, -122.41310119628906},
+ {37.73135334055843, -122.41310119628906},
+ {37.73135334055843, -122.44640350341795},
+ };
+ MGLPolygonFeature *leftFeature = [MGLPolygonFeature polygonWithCoordinates:leftCoords count:5];
+ leftFeature.attributes = @{@"fill": @(YES)};
+
+ MGLPolygonFeature *rightFeature = [MGLPolygonFeature polygonWithCoordinates:rightCoords count:5];
+ rightFeature.attributes = @{@"opacity": @(0.5)};
+
+ MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shape-source" features:@[leftFeature, rightFeature] options:nil];
+ [self.mapView.style addSource:shapeSource];
+
+ // source, categorical function that sets any feature with a "fill" attribute value of true to red color and anything without to green
+ MGLFillStyleLayer *fillStyleLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fill-layer" source:shapeSource];
+ NSDictionary *stops = @{@(YES): [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor greenColor]]};
+ NSDictionary *fillColorOptions = @{MGLStyleFunctionOptionDefaultValue: [MGLStyleValue<UIColor *> valueWithRawValue:[UIColor redColor]]};
+ fillStyleLayer.fillColor = [MGLStyleValue<UIColor *> valueWithInterpolationMode:MGLInterpolationModeCategorical
+ sourceStops:stops
+ attributeName:@"fill"
+ options:fillColorOptions];
+
+ // source, identity function that sets any feature with an "opacity" attribute to use that value and anything without to 1.0
+ NSDictionary *fillOpacityOptions = @{MGLStyleFunctionOptionDefaultValue: [MGLStyleValue<NSNumber *> valueWithRawValue:@(1.0)]};
+ fillStyleLayer.fillOpacity = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity
+ sourceStops:nil
+ attributeName:@"opacity"
+ options:fillOpacityOptions];
+ [self.mapView.style addLayer:fillStyleLayer];
+}
+
- (void)addLatLonGrid
{
MGLComputedShapeSource *source = [[MGLComputedShapeSource alloc] initWithIdentifier:@"latlon"
@@ -1258,6 +1383,39 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
}
}
+- (void)styleLabelLanguageForLayersNamed:(NSArray<NSString *> *)layers
+{
+ _usingLocaleBasedCountryLabels = !_usingLocaleBasedCountryLabels;
+ NSString *bestLanguageForUser = [NSString stringWithFormat:@"{name_%@}", [self bestLanguageForUser]];
+ NSString *language = _usingLocaleBasedCountryLabels ? bestLanguageForUser : @"{name}";
+
+ for (NSString *layerName in layers) {
+ MGLSymbolStyleLayer *layer = (MGLSymbolStyleLayer *)[self.mapView.style layerWithIdentifier:layerName];
+
+ if ([layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
+ if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) {
+ MGLStyleConstantValue *label = (MGLStyleConstantValue<NSString *> *)layer.text;
+ if ([label.rawValue hasPrefix:@"{name"]) {
+ layer.text = [MGLStyleValue valueWithRawValue:language];
+ }
+ }
+ else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
+ NSMutableDictionary *stops = function.stops.mutableCopy;
+ [stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue<NSString *> *stop, BOOL *done) {
+ if ([stop.rawValue hasPrefix:@"{name"]) {
+ stops[zoomLevel] = [MGLStyleValue<NSString *> valueWithRawValue:language];
+ }
+ }];
+ function.stops = stops;
+ layer.text = function;
+ }
+ } else {
+ NSLog(@"%@ is not a symbol style layer", layerName);
+ }
+ }
+}
+
- (NSString *)bestLanguageForUser
{
NSArray *supportedLanguages = @[ @"en", @"es", @"fr", @"de", @"ru", @"zh" ];
@@ -1330,7 +1488,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
} else {
message = [NSString stringWithFormat:@"There are %@ visible annotations.", visibleAnnotationCount];
}
-
+
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Visible Annotations" message:message preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertController animated:YES completion:nil];
@@ -1381,7 +1539,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"];
}
}
-
+
MBXDroppedPinAnnotation *pin = [[MBXDroppedPinAnnotation alloc] init];
pin.coordinate = [self.mapView convertPoint:point
toCoordinateFromView:self.mapView];
@@ -1396,7 +1554,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
static NSArray *styleNames;
static NSArray *styleURLs;
-
+
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
styleNames = @[
@@ -1416,7 +1574,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[MGLStyle satelliteStreetsStyleURLWithVersion:MGLStyleDefaultVersion],
];
NSAssert(styleNames.count == styleURLs.count, @"Style names and URLs don’t match.");
-
+
// Make sure defaultStyleURLs is up-to-date.
unsigned numMethods = 0;
Method *methods = class_copyMethodList(object_getClass([MGLStyle class]), &numMethods);
@@ -1435,11 +1593,11 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"MGLStyle provides %u default styles but iosapp only knows about %lu of them.",
numStyleURLMethods, (unsigned long)styleNames.count);
});
-
+
self.styleIndex = (self.styleIndex + 1) % styleNames.count;
self.mapView.styleURL = styleURLs[self.styleIndex];
-
+
UIButton *titleButton = (UIButton *)self.navigationItem.titleView;
[titleButton setTitle:styleNames[self.styleIndex] forState:UIControlStateNormal];
}
@@ -1490,7 +1648,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
return nil;
}
-
+
MBXAnnotationView *annotationView = (MBXAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:MBXViewControllerAnnotationViewReuseIdentifer];
if (!annotationView)
{
@@ -1503,7 +1661,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
// Comment out the pin dropping functionality in the handleLongPress:
// method in this class to make draggable annotation views play nice.
annotationView.draggable = YES;
-
+
// Uncomment to force annotation view to maintain a constant size when
// the map is tilted. By default, annotation views will shrink and grow
// as they move towards and away from the horizon. Relatedly, annotations
@@ -1694,7 +1852,15 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
{
queuedAnnotations += queue.count;
}
- self.hudLabel.text = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (unsigned long)mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations];
+ self.hudLabel.text = [NSString stringWithFormat:@" Visible: %ld Queued: %ld", (unsigned long)mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations];
+ } else if (self.showZoomLevelEnabled) {
+ self.hudLabel.text = [NSString stringWithFormat:@" Zoom: %.2f", self.mapView.zoomLevel];
+ }
+}
+
+- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
+ if (self.showZoomLevelEnabled) {
+ self.hudLabel.text = [NSString stringWithFormat:@" Zoom: %.2f", self.mapView.zoomLevel];
}
}
diff --git a/platform/ios/app/de.lproj/Localizable.strings b/platform/ios/app/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/de.lproj/Localizable.strings
diff --git a/platform/ios/app/es.lproj/Localizable.strings b/platform/ios/app/es.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/es.lproj/Localizable.strings
diff --git a/platform/ios/app/fr.lproj/Localizable.strings b/platform/ios/app/fr.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/fr.lproj/Localizable.strings
diff --git a/platform/ios/app/ja.lproj/Localizable.strings b/platform/ios/app/ja.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/ja.lproj/Localizable.strings
diff --git a/platform/ios/app/lt.lproj/Localizable.strings b/platform/ios/app/lt.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/lt.lproj/Localizable.strings
diff --git a/platform/ios/app/pl.lproj/Localizable.strings b/platform/ios/app/pl.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/pl.lproj/Localizable.strings
diff --git a/platform/ios/app/pt-BR.lproj/Localizable.strings b/platform/ios/app/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/pt-BR.lproj/Localizable.strings
diff --git a/platform/ios/app/ru.lproj/Localizable.strings b/platform/ios/app/ru.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/ru.lproj/Localizable.strings
diff --git a/platform/ios/app/sv.lproj/Localizable.strings b/platform/ios/app/sv.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/sv.lproj/Localizable.strings
diff --git a/platform/ios/app/uk.lproj/Localizable.strings b/platform/ios/app/uk.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/uk.lproj/Localizable.strings
diff --git a/platform/ios/app/vi.lproj/Localizable.strings b/platform/ios/app/vi.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/vi.lproj/Localizable.strings
diff --git a/platform/ios/app/zh-Hans.lproj/Localizable.strings b/platform/ios/app/zh-Hans.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/zh-Hans.lproj/Localizable.strings
diff --git a/platform/ios/app/zh-Hant.lproj/Localizable.strings b/platform/ios/app/zh-Hant.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/ios/app/zh-Hant.lproj/Localizable.strings
diff --git a/platform/ios/benchmark/MBXBenchViewController.mm b/platform/ios/benchmark/MBXBenchViewController.mm
index 4f26d0cb1d..d4629e2521 100644
--- a/platform/ios/benchmark/MBXBenchViewController.mm
+++ b/platform/ios/benchmark/MBXBenchViewController.mm
@@ -52,7 +52,7 @@
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
-
+
if ([MGLAccountManager accessToken].length) {
[self startBenchmarkIteration];
} else {
@@ -62,7 +62,7 @@
textField.autocorrectionType = UITextAutocorrectionTypeNo;
textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
}];
-
+
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[self startBenchmarkIteration];
}]];
@@ -72,11 +72,11 @@
[[NSUserDefaults standardUserDefaults] setObject:accessToken forKey:MBXMapboxAccessTokenDefaultsKey];
[MGLAccountManager setAccessToken:accessToken];
[self.mapView reloadStyle:self];
-
+
[self startBenchmarkIteration];
}];
[alertController addAction:OKAction];
-
+
if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
alertController.preferredAction = OKAction;
}
diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake
index 1150171c54..72e1c88525 100644
--- a/platform/ios/config.cmake
+++ b/platform/ios/config.cmake
@@ -44,7 +44,9 @@ macro(mbgl_platform_core)
PRIVATE platform/default/utf.cpp
# Image handling
+ PRIVATE platform/darwin/mbgl/util/image+MGLAdditions.hpp
PRIVATE platform/darwin/src/image.mm
+ PRIVATE platform/default/png_writer.cpp
# Headless view
PRIVATE platform/default/mbgl/gl/headless_backend.cpp
@@ -56,6 +58,8 @@ macro(mbgl_platform_core)
PRIVATE platform/default/mbgl/gl/offscreen_view.hpp
# Thread pool
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
)
diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index e91bc0b1cc..6c2693cbbf 100644
--- a/platform/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)
-The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.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 iOS SDK 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.
![Mapbox iOS SDK screenshots](img/screenshot.png)
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
index 753eb7200c..a65d07bdd1 100644
--- a/platform/ios/docs/guides/For Style Authors.md
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -29,8 +29,9 @@ underneath.
The user location annotation view, the attribution button, any buttons in
callout views, and any items in the navigation bar are influenced by your
application’s tint color, so choose a tint color that constrasts well with your
-map style. If you intend your style to be used in the dark, consider the impact
-that Night Shift may have on your style’s colors.
+map style.
+If you intend your style to be used in the dark, consider the impact that Night
+Shift may have on your style’s colors.
### Typography and graphics
@@ -127,7 +128,7 @@ In style JSON | In the SDK
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
-`image` and `video` sources are not supported.
+`canvas`, `image`, and `video` sources are not supported.
### Tile sources
@@ -275,9 +276,10 @@ Array (`-offset`, `-translate`) | `NSValue.CGVectorValue` | `NSValue.cgVectorVal
Array (`-padding`) | `NSValue.UIEdgeInsetsValue` | `NSValue.uiEdgeInsetsValue`
For padding attributes, note that the arguments to
-`UIEdgeInsetsMake()` in Objective-C and
-`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
-order, in contrast to the clockwise order defined by the style specification.
+`UIEdgeInsetsMake()` in Objective-C and `UIEdgeInsets(top:left:bottom:right:)`
+in Swift
+are specified in counterclockwise order, in contrast to the clockwise order
+defined by the style specification.
## Filtering sources
diff --git a/platform/ios/docs/guides/Gesture Recognizers.md b/platform/ios/docs/guides/Gesture Recognizers.md
new file mode 100644
index 0000000000..08e4c150e1
--- /dev/null
+++ b/platform/ios/docs/guides/Gesture Recognizers.md
@@ -0,0 +1,38 @@
+# User Interactions
+
+The Mapbox iOS SDK provides a set of built-in gesture recognizers. You can customize or supplement these gestures according to your use case. You see what gesture recognizers are on your `MGLMapView` by accessing the `gestureRecognizers` property on your map.
+
+## Configuring user interaction
+
+Several properties on an `MGLMapView` provide ways to enable or disable a set of gesture recognizers. Boolean values are set to `YES` by default.
+
+- `zoomEnabled` - Allows the user to zoom in or out by pinching two fingers, double-tapping, tapping with two fingers, or double-tapping then dragging vertically. Accepts Boolean values.
+- `scrollEnabled` - Allows the user to scroll by dragging or swiping one finger. Accepts Boolean values.
+- `rotateEnabled` - Allows the user to rotate by moving two fingers in a circular motion. Accepts Boolean values.
+- `pitchEnabled` - Allows the user to tilt the map by vertically dragging two fingers. Accepts Boolean values.
+- `decelerationRate` - Determines the rate of deceleration after the user lifts their finger. You can set the value using the `MGLMapViewDecelerationRateNormal`, `MGLMapViewDecelerationRateFast`, or `MGLMapViewDecelerationRateImmediate` constants.
+
+## Individual gestures
+
+|Gesture | Description | Related Property |
+|:-------:|----------------| -----------|
+|Pinch | Zooms in or out on the map's anchor point | `zoomEnabled` |
+|Rotation | Changes the MGLMapView direction based on the user rotating two fingers in a circular motion | `rotateEnabled` |
+|Single tap | Selects/deselects the annotation that you tap. | |
+|Double tap | Zooms in on the map's anchor point | `zoomEnabled` |
+|Two-finger tap | Zooms out with the map's anchor point centered | `zoomEnabled` |
+|Pan | Scrolls across mapView (_note: if_ `MGLUserTrackingModeFollow` _is being used, it will be disabled once the user pans_)| `scrollEnabled` |
+|Two-finger drag | Adjusts the pitch of the `MGLMapView` | `pitchEnabled` |
+|One-finger zoom | Tap twice; on second tap, hold your finger on the map and pan up to zoom in, or down to zoom out | `zoomEnabled`|
+
+![quick zoom](img/user-interaction/quickzoom.gif) ![rotation](img/user-interaction/RotateSydney.gif)
+
+## Adding custom gesture recognizers
+
+You can add `UIGestureRecognizers` to your map programmatically or via storyboard. Adding custom responses to gesture recognizers can enhance your user's experience, but try to use standard gestures where possible.
+
+The gesture recognizers that you add will take priority over the built-in gesture recognizer. You can also set up your own gesture recognizer to work simultaneously with built-in gesture recognizers by using `-gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:`, allowing you to enhance already existing gesture recognizers.
+
+You can also add gesture recognizers that are only called when the default gesture recognizer fails (and vice versa), such as when a user taps on a part of the map that is not an annotation. The documentation for [MGLMapView](Classes/MGLMapView.html) includes an example of how to create a fallback gesture recognizer.
+
+If you would like to disable a specific set of gesture recognizers, such as zoom, you can set the Boolean value for the appropriate property to `NO`. You can then add your own gesture recognizers to perform those actions.
diff --git a/platform/ios/docs/img/user-interaction/RotateSydney.gif b/platform/ios/docs/img/user-interaction/RotateSydney.gif
new file mode 100644
index 0000000000..59d44d5636
--- /dev/null
+++ b/platform/ios/docs/img/user-interaction/RotateSydney.gif
Binary files differ
diff --git a/platform/ios/docs/img/user-interaction/quickzoom.gif b/platform/ios/docs/img/user-interaction/quickzoom.gif
new file mode 100644
index 0000000000..ce4515825c
--- /dev/null
+++ b/platform/ios/docs/img/user-interaction/quickzoom.gif
Binary files differ
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index b1a763bcf1..2e5b024fdc 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -1,6 +1,6 @@
# [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)
-The Mapbox iOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 7.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 iOS SDK 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.
For more information, check out the [Mapbox iOS SDK 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.
@@ -16,7 +16,7 @@ Integrating the Mapbox iOS SDK requires Xcode 7.3 or higher.
### Dynamic framework
-This is the recommended workflow for manually integrating the SDK into an application targeting iOS 8 and above:
+This is the recommended workflow for manually integrating the SDK into an application:
1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework from the `dynamic` folder into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish.
@@ -33,7 +33,7 @@ bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Mapbox.framework/strip-fra
### Static framework
-If your application targets iOS 7.x, you’ll need to install the static framework instead:
+You can alternatively install the SDK as a static framework:
1. Drag Mapbox.bundle and Mapbox.framework from the `static` folder into the Project navigator. In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. Open the project editor and select your application target to verify that the following changes occurred automatically:
diff --git a/platform/ios/framework/Settings.bundle/de.lproj/Root.strings b/platform/ios/framework/Settings.bundle/de.lproj/Root.strings
new file mode 100644
index 0000000000..c57189d4af
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/de.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Privatsphäre-Einstellungen";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox-Telemetrie";
+"TELEMETRY_GROUP_FOOTER" = "Diese Einstellung erlaubt der Applikation, anonymisierte Orts- und Nutzungsdaten an Mapbox zu senden.";
diff --git a/platform/ios/framework/Settings.bundle/es.lproj/Root.strings b/platform/ios/framework/Settings.bundle/es.lproj/Root.strings
new file mode 100644
index 0000000000..bb0c52dcde
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/es.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Ajustes de privacidad";
+"TELEMETRY_SWITCH_TITLE" = "Telemetría Mapbox";
+"TELEMETRY_GROUP_FOOTER" = "Esta configuración permite que la aplicación comparta datos anónimos de ubicación y uso con Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/fr.lproj/Root.strings b/platform/ios/framework/Settings.bundle/fr.lproj/Root.strings
new file mode 100644
index 0000000000..c386d9846d
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/fr.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Paramètres de confidentialité";
+"TELEMETRY_SWITCH_TITLE" = "Télémétrie Mapbox";
+"TELEMETRY_GROUP_FOOTER" = "Cette option permet à l’application de partager des données de localisation et d’utilisation anonymes avec Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/lt.lproj/Root.strings b/platform/ios/framework/Settings.bundle/lt.lproj/Root.strings
new file mode 100644
index 0000000000..832b16608b
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/lt.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Privatumo nustatymai";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox Telemetrija";
+"TELEMETRY_GROUP_FOOTER" = "Šis nustatymas leidžia programėlei dalintis su Mapbox anonimizuota lokacija bei naudojimosi duomenimis.";
diff --git a/platform/ios/framework/Settings.bundle/pl.lproj/Root.strings b/platform/ios/framework/Settings.bundle/pl.lproj/Root.strings
new file mode 100644
index 0000000000..4cf2c71381
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/pl.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Ustawienia prywatności";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox Telemetria";
+"TELEMETRY_GROUP_FOOTER" = "Ta opcja pozwala aplikacji na anonimowe wysyłanie lokalizacji i danych do Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/pt-BR.lproj/Root.strings b/platform/ios/framework/Settings.bundle/pt-BR.lproj/Root.strings
new file mode 100644
index 0000000000..5b81fb66eb
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/pt-BR.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Configurações de privacidade";
+"TELEMETRY_SWITCH_TITLE" = "Telemetria do Mapbox";
+"TELEMETRY_GROUP_FOOTER" = "Essa configuração permite que o aplicativo compartilhe dados de localização e uso anônimos com o Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/ru.lproj/Root.strings b/platform/ios/framework/Settings.bundle/ru.lproj/Root.strings
new file mode 100644
index 0000000000..2883ec4b87
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/ru.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Настройки приватности";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox Телеметрия";
+"TELEMETRY_GROUP_FOOTER" = "Эта настройка разрешает приложению отправлять анонимную позицию и данные об использовании в Mapbox";
diff --git a/platform/ios/framework/Settings.bundle/sv.lproj/Root.strings b/platform/ios/framework/Settings.bundle/sv.lproj/Root.strings
new file mode 100644
index 0000000000..f8324c14c4
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/sv.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Sekretessinställningar";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox Telemetri";
+"TELEMETRY_GROUP_FOOTER" = "Denna inställning tillåter applikationen att dela anonymiserad plats och användningsdata med Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/uk.lproj/Root.strings b/platform/ios/framework/Settings.bundle/uk.lproj/Root.strings
new file mode 100644
index 0000000000..5d2bfd648e
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/uk.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Налаштування конфіденційності";
+"TELEMETRY_SWITCH_TITLE" = "Телеметрія Mapbox";
+"TELEMETRY_GROUP_FOOTER" = "Ці налаштування дозволяють застосунку надсилати анонімізовані дані про місце знаходження та використання даних до Mapbox.";
diff --git a/platform/ios/framework/Settings.bundle/vi.lproj/Root.strings b/platform/ios/framework/Settings.bundle/vi.lproj/Root.strings
new file mode 100644
index 0000000000..e156d9937a
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/vi.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "Thiết lập Quyền riêng tư";
+"TELEMETRY_SWITCH_TITLE" = "Trình viễn trắc Mapbox";
+"TELEMETRY_GROUP_FOOTER" = "Tùy chọn này cho phép ứng dụng gửi cho Mapbox các vị trí và dữ liệu sử dụng được vô danh hóa.";
diff --git a/platform/ios/framework/Settings.bundle/zh-Hant.lproj/Root.strings b/platform/ios/framework/Settings.bundle/zh-Hant.lproj/Root.strings
new file mode 100644
index 0000000000..13a8d57020
--- /dev/null
+++ b/platform/ios/framework/Settings.bundle/zh-Hant.lproj/Root.strings
@@ -0,0 +1,3 @@
+"TELEMETRY_GROUP_TITLE" = "隱私設置";
+"TELEMETRY_SWITCH_TITLE" = "Mapbox傳感數據";
+"TELEMETRY_GROUP_FOOTER" = "此設置允許應用將用戶位置和數據以匿名的方式分享給Mapbox。";
diff --git a/platform/ios/framework/strip-frameworks.sh b/platform/ios/framework/strip-frameworks.sh
index 9deb404ca1..686541566a 100755
--- a/platform/ios/framework/strip-frameworks.sh
+++ b/platform/ios/framework/strip-frameworks.sh
@@ -35,9 +35,19 @@ code_sign() {
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1"
}
-echo "Stripping frameworks"
+# Set working directory to product’s embedded frameworks
cd "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
+if [ "$ACTION" = "install" ]; then
+ echo "Copy .bcsymbolmap files to .xcarchive"
+ find . -name '*.bcsymbolmap' -type f -exec mv {} "${CONFIGURATION_BUILD_DIR}" \;
+else
+ # Delete *.bcsymbolmap files from framework bundle unless archiving
+ find . -name '*.bcsymbolmap' -type f -exec rm -rf "{}" +\;
+fi
+
+echo "Stripping frameworks"
+
for file in $(find . -type f -perm +111); do
# Skip non-dynamic libraries
if ! [[ "$(file "$file")" == *"dynamically linked shared library"* ]]; then
@@ -61,10 +71,3 @@ for file in $(find . -type f -perm +111); do
fi
done
-if [ "$ACTION" = "install" ]; then
- echo "Copy .bcsymbolmap files to .xcarchive"
- find . -name '*.bcsymbolmap' -type f -exec mv {} "${CONFIGURATION_BUILD_DIR}" \;
-else
- # Delete *.bcsymbolmap files from framework bundle unless archiving
- find . -name '*.bcsymbolmap' -type f -exec rm -rf "{}" +\;
-fi
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index a31d43dbbc..56bcda32f2 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
+ 1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
+ 1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
30E578171DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578111DAA7D690050F07E /* UIImage+MGLAdditions.h */; };
30E578191DAA855E0050F07E /* UIImage+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 30E578121DAA7D690050F07E /* UIImage+MGLAdditions.mm */; };
@@ -74,6 +76,8 @@
354B83981D2E873E005D9406 /* MGLUserLocationAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 354B83951D2E873E005D9406 /* MGLUserLocationAnnotationView.m */; };
354B83991D2E873E005D9406 /* MGLUserLocationAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 354B83951D2E873E005D9406 /* MGLUserLocationAnnotationView.m */; };
354B839C1D2E9B48005D9406 /* MBXUserLocationAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 354B839B1D2E9B48005D9406 /* MBXUserLocationAnnotationView.m */; };
+ 3557F7B01E1D27D300CCA5E6 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3557F7B21E1D27D300CCA5E6 /* MGLDistanceFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */; };
35599DED1D46F14E0048254D /* MGLStyleValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35599DEA1D46F14E0048254D /* MGLStyleValue.mm */; };
35599DEE1D46F14E0048254D /* MGLStyleValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35599DEA1D46F14E0048254D /* MGLStyleValue.mm */; };
3566C7661D4A77BA008152BC /* MGLShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 3566C7641D4A77BA008152BC /* MGLShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -96,6 +100,7 @@
357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */; };
357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */; };
357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */; };
+ 3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */; };
3599A3E61DF708BC00E77FB2 /* MGLStyleValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */; };
359F57461D2FDDA6005217F1 /* MGLUserLocationAnnotationView_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */; };
35B82BF81D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35B82BF61D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h */; };
@@ -166,7 +171,12 @@
556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D71E1D085500E2C41B /* MGLVersionNumber.m */; };
556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 558DE7A01E5615E400C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */; };
+ 558DE7A11E5615E400C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */; };
+ 558DE7A21E5615E400C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE79F1E5615E400C7916D /* MGLFoundation.mm */; };
+ 558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE79F1E5615E400C7916D /* MGLFoundation.mm */; };
55D8C9961D0F18CE00F42F10 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */; };
+ 55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */; };
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */; };
7E016D7E1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
7E016D7F1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */; };
@@ -176,6 +186,8 @@
7E016D851D9E890300A29A21 /* MGLPolygon+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */; };
7E016D861D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
7E016D871D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */; };
+ 968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 96E027231E57C76E004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027251E57C76E004B8E66 /* Localizable.strings */; };
88B079A61E363A7200834FAB /* MGLAbstractShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 88B079A51E36371A00834FAB /* MGLAbstractShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
88B079A71E363A7300834FAB /* MGLAbstractShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 88B079A51E36371A00834FAB /* MGLAbstractShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
88DDFB291DCB7A9200B53BDD /* MGLComputedShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 88F0C0811DC8FD8C002DB7AE /* MGLComputedShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -213,7 +225,6 @@
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */; };
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */; };
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */; };
- DA2E88641CC0382C00F24E7B /* MGLOfflineStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA2E885F1CC0382C00F24E7B /* MGLOfflineStorageTests.m */; };
DA2E88651CC0382C00F24E7B /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */; };
DA35A29E1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -240,7 +251,7 @@
DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
DA72620B1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- DA72620C1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */; };
+ DA72620C1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
DA72620D1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */; };
DA72620E1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */; };
DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -347,6 +358,7 @@
DA8963381CC549A100684375 /* sprites in Resources */ = {isa = PBXBuildFile; fileRef = DA8963341CC549A100684375 /* sprites */; };
DA8963391CC549A100684375 /* styles in Resources */ = {isa = PBXBuildFile; fileRef = DA8963351CC549A100684375 /* styles */; };
DA89633A1CC549A100684375 /* tiles in Resources */ = {isa = PBXBuildFile; fileRef = DA8963361CC549A100684375 /* tiles */; };
+ DAA32CC31E4C6B65006F8D24 /* MGLDistanceFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */; };
DAA4E4051CBB5C9E00178DFB /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA4E4041CBB5C9E00178DFB /* ImageIO.framework */; };
DAA4E4071CBB5CBF00178DFB /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA4E4061CBB5CBF00178DFB /* MobileCoreServices.framework */; };
DAA4E4081CBB6C9500178DFB /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; };
@@ -521,6 +533,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
20DABE861DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Foundation.strings"; sourceTree = "<group>"; };
20DABE881DF78148007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
20DABE8A1DF78149007AC5FF /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Root.strings"; sourceTree = "<group>"; };
@@ -560,6 +573,8 @@
354B83951D2E873E005D9406 /* MGLUserLocationAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLUserLocationAnnotationView.m; sourceTree = "<group>"; };
354B839A1D2E9B48005D9406 /* MBXUserLocationAnnotationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXUserLocationAnnotationView.h; sourceTree = "<group>"; };
354B839B1D2E9B48005D9406 /* MBXUserLocationAnnotationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXUserLocationAnnotationView.m; sourceTree = "<group>"; };
+ 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLDistanceFormatter.h; sourceTree = "<group>"; };
+ 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLDistanceFormatter.m; sourceTree = "<group>"; };
35599DEA1D46F14E0048254D /* MGLStyleValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLStyleValue.mm; sourceTree = "<group>"; };
3566C7641D4A77BA008152BC /* MGLShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeSource.h; sourceTree = "<group>"; };
3566C7651D4A77BA008152BC /* MGLShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeSource.mm; sourceTree = "<group>"; };
@@ -575,6 +590,7 @@
357F09091DF84F3800941873 /* MGLStyleValueTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MGLStyleValueTests.h; path = ../../darwin/test/MGLStyleValueTests.h; sourceTree = "<group>"; };
357FE2DB1E02D2B20068B753 /* NSCoder+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSCoder+MGLAdditions.h"; path = "../../darwin/src/NSCoder+MGLAdditions.h"; sourceTree = "<group>"; };
357FE2DC1E02D2B20068B753 /* NSCoder+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "NSCoder+MGLAdditions.mm"; path = "../../darwin/src/NSCoder+MGLAdditions.mm"; sourceTree = "<group>"; };
+ 3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLDistanceFormatterTests.m; path = ../../darwin/test/MGLDistanceFormatterTests.m; sourceTree = "<group>"; };
3599A3E51DF708BC00E77FB2 /* MGLStyleValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLStyleValueTests.m; path = ../../darwin/test/MGLStyleValueTests.m; sourceTree = "<group>"; };
359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationAnnotationView_Private.h; sourceTree = "<group>"; };
35B82BF61D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -622,22 +638,43 @@
554180411D2E97DE00012372 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; };
556660C91E1BF3A900E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; };
556660D71E1D085500E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
+ 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
+ 558DE79F1E5615E400C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = "<group>"; };
55D8C9951D0F18CE00F42F10 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
+ 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflineStorageTests.mm; path = ../../darwin/test/MGLOfflineStorageTests.mm; sourceTree = "<group>"; };
6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MGLDocumentationExampleTests.swift; path = ../../darwin/test/MGLDocumentationExampleTests.swift; sourceTree = "<group>"; };
7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolyline+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D7D1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolyline+MGLAdditions.m"; sourceTree = "<group>"; };
7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLPolygon+MGLAdditions.h"; sourceTree = "<group>"; };
7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLPolygon+MGLAdditions.m"; sourceTree = "<group>"; };
+ 9660916B1E5BBFD700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 9660916C1E5BBFD900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 9660916E1E5BBFDC00A9A03B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 9660916F1E5BBFDE00A9A03B /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 968F36B41E4D0FC6003A5522 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E027241E57C76E004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
88B079A51E36371A00834FAB /* MGLAbstractShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAbstractShapeSource.h; sourceTree = "<group>"; };
88DDFB2C1DCBC21700B53BDD /* MGLAbstractShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAbstractShapeSource.mm; sourceTree = "<group>"; tabWidth = 4; };
+ 96E027271E57C77A004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E027281E57C7DB004B8E66 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ 96E027291E57C7DE004B8E66 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ 96E0272A1E57C7DF004B8E66 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
88DDFB311DCBC36E00B53BDD /* MGLAbstractShapeSource_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLAbstractShapeSource_Private.h; sourceTree = "<group>"; };
88F0C0811DC8FD8C002DB7AE /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = "<group>"; };
+ 96E0272B1E57C7E3004B8E66 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E0272C1E57C7E5004B8E66 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
88F0C0821DC8FD8C002DB7AE /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = "<group>"; tabWidth = 4; };
+ 96E0272D1E57C7E6004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E0272E1E57C7E7004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; 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>"; };
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Private.h; sourceTree = "<group>"; };
+ DA1AC01B1E5B8774006DF1D6 /* lt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA1AC01C1E5B87EC006DF1D6 /* lt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Root.strings; sourceTree = "<group>"; };
+ DA1AC0201E5B8917006DF1D6 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA1DC94A1CB6C1C2006E619F /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DA1DC9501CB6C1C2006E619F /* MBXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXAppDelegate.h; sourceTree = "<group>"; };
DA1DC9531CB6C1C2006E619F /* MBXViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXViewController.h; sourceTree = "<group>"; };
@@ -667,7 +704,6 @@
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = "<group>"; };
DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = "<group>"; };
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
- DA2E885F1CC0382C00F24E7B /* MGLOfflineStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineStorageTests.m; path = ../../darwin/test/MGLOfflineStorageTests.m; sourceTree = "<group>"; };
DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = "<group>"; };
DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = "<group>"; };
@@ -684,10 +720,22 @@
DA35D0871E1A6309007DED41 /* one-liner.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "one-liner.json"; path = "../../darwin/test/one-liner.json"; sourceTree = "<group>"; };
DA3C6FF21E2859E700F962BE /* test-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "test-Bridging-Header.h"; path = "../../darwin/test/test-Bridging-Header.h"; sourceTree = "<group>"; };
DA4A26961CB6E795000B7809 /* Mapbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Mapbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ DA6023F11E4CE94300DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DA6023F21E4CE94800DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; };
DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; };
+ DA737ADA1E59139D00AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DA737ADB1E5913BA00AD2CDE /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737ADC1E59145700AD2CDE /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Root.strings; sourceTree = "<group>"; };
+ DA737AE01E59150A00AD2CDE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pl; path = pl.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DA737AE11E59157600AD2CDE /* pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Root.strings; sourceTree = "<group>"; };
+ DA737AE51E5916D400AD2CDE /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DA737AE61E59171700AD2CDE /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Root.strings; sourceTree = "<group>"; };
+ DA737AE71E59172C00AD2CDE /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737AE91E5917C300AD2CDE /* uk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737AEA1E5917EF00AD2CDE /* uk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Root.strings; sourceTree = "<group>"; };
DA737EE01D056A4E005BDA16 /* MGLMapViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapViewDelegate.h; sourceTree = "<group>"; };
DA821D041CCC6D59007508D4 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
DA821D051CCC6D59007508D4 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
@@ -786,6 +834,25 @@
DA8F25B91D51D2570010E6B5 /* MGLStyleLayerTests.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.mm.ejs; path = ../test/MGLStyleLayerTests.mm.ejs; sourceTree = "<group>"; };
DA8F25BA1D51D2570010E6B5 /* MGLStyleLayer.h.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.h.ejs; sourceTree = "<group>"; };
DA8F25BB1D51D2570010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
+ DA9C012B1E4C7AD900C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "pt-BR.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
+ DA9C012C1E4C7ADB00C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "pt-BR.lproj/Foundation.stringsdict"; sourceTree = "<group>"; };
+ DA9C012D1E4C7B1F00C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ DA9C012E1E4C7B6100C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Root.strings"; sourceTree = "<group>"; };
+ DAA32CA11E4C44DB006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DAA32CA21E4C44DD006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DAA32CA31E4C44F1006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CA41E4C4502006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CA51E4C450F006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Root.strings; sourceTree = "<group>"; };
+ DAA32CA91E4C4919006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
+ DAA32CAB1E4C491A006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DAA32CAC1E4C4971006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CB11E4C4C8A006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Root.strings; sourceTree = "<group>"; };
+ DAA32CB51E4C4CF4006F8D24 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CB71E4C4ED8006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CB81E4C4EE6006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Root.strings; sourceTree = "<group>"; };
+ DAA32CBC1E4C4F5D006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CBD1E4C4F62006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CBE1E4C4F71006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Root.strings; sourceTree = "<group>"; };
DAA4E4021CBB5C2F00178DFB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
DAA4E4041CBB5C9E00178DFB /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; };
DAA4E4061CBB5CBF00178DFB /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
@@ -817,6 +884,9 @@
DAF0D80F1DFE0EA000B28378 /* MGLRasterSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource_Private.h; sourceTree = "<group>"; };
DAF0D8121DFE0EC500B28378 /* MGLVectorSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorSource_Private.h; sourceTree = "<group>"; };
DAF0D8171DFE6B2800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
+ DAFBD0D21E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Foundation.strings"; sourceTree = "<group>"; };
+ DAFBD0D31E3FA7A1000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ DAFBD0D41E3FA7A2000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Root.strings"; sourceTree = "<group>"; };
DD0902A21DB18DE700C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
DD4823721D94AE6C00EB71B7 /* fill_filter_style.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = fill_filter_style.json; sourceTree = "<group>"; };
@@ -918,8 +988,8 @@
DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */,
353933FA1D3FB7C0003F57D7 /* MGLRasterStyleLayer.h */,
35136D411D42274500C20EFD /* MGLRasterStyleLayer.mm */,
- 35D13AB51D3D15E300AFB4E0 /* MGLStyleLayer.h */,
35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */,
+ 35D13AB51D3D15E300AFB4E0 /* MGLStyleLayer.h */,
35D13AB61D3D15E300AFB4E0 /* MGLStyleLayer.mm */,
353933FD1D3FB7DD003F57D7 /* MGLSymbolStyleLayer.h */,
35136D441D42275100C20EFD /* MGLSymbolStyleLayer.mm */,
@@ -932,6 +1002,7 @@
35599DA21D4682B60048254D /* Styling */ = {
isa = PBXGroup;
children = (
+ 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */,
35599DB81D46AD7F0048254D /* Categories */,
353933F01D3FB6BA003F57D7 /* Layers */,
35136D491D4277EA00C20EFD /* Sources */,
@@ -1064,6 +1135,7 @@
DD4823741D94AE6C00EB71B7 /* numeric_filter_style.json */,
DA1DC95E1CB6C1C2006E619F /* Info.plist */,
DA1DC99C1CB6E076006E619F /* Default-568h@2x.png */,
+ 96E027251E57C76E004B8E66 /* Localizable.strings */,
DA1DC94D1CB6C1C2006E619F /* Supporting Files */,
);
name = "Demo App";
@@ -1117,13 +1189,14 @@
DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */,
6407D66F1E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift */,
DD58A4C51D822BD000E1F038 /* MGLExpressionTests.mm */,
+ 3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */,
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */,
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */,
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */,
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */,
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */,
- DA2E885F1CC0382C00F24E7B /* MGLOfflineStorageTests.m */,
+ 55E2AD121E5B125400E8C587 /* MGLOfflineStorageTests.mm */,
35B8E08B1D6C8B5100E768D2 /* MGLPredicateTests.mm */,
DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */,
556660D71E1D085500E2C41B /* MGLVersionNumber.m */,
@@ -1167,6 +1240,8 @@
DAF0D8171DFE6B2800B28378 /* MGLAttributionInfo_Private.h */,
DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */,
556660C91E1BF3A900E2C41B /* MGLFoundation.h */,
+ 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */,
+ 558DE79F1E5615E400C7916D /* MGLFoundation.mm */,
DA8847E21CBAFA5100AB86E3 /* MGLMapCamera.h */,
DA8848031CBAFA6200AB86E3 /* MGLMapCamera.mm */,
DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */,
@@ -1334,6 +1409,8 @@
DA35A2B01CCA141D00E826B2 /* MGLCompassDirectionFormatter.m */,
DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */,
DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */,
+ 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */,
+ 3557F7AF1E1D27D300CCA5E6 /* MGLDistanceFormatter.m */,
);
name = Formatters;
sourceTree = "<group>";
@@ -1529,6 +1606,7 @@
DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */,
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */,
DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */,
+ 558DE7A01E5615E400C7916D /* MGLFoundation_Private.h in Headers */,
DA88483D1CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h in Headers */,
DA17BE301CC4BAC300402C41 /* MGLMapView_Private.h in Headers */,
DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */,
@@ -1557,6 +1635,7 @@
DAD1656C1CF41981001FF4B9 /* MGLFeature.h in Headers */,
40EDA1C01CFE0E0200D9EA68 /* MGLAnnotationContainerView.h in Headers */,
DA88484F1CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h in Headers */,
+ 1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */,
DA8847F21CBAFA5100AB86E3 /* MGLMapCamera.h in Headers */,
3538AA1D1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */,
DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */,
@@ -1564,6 +1643,7 @@
DA8848851CBB033F00AB86E3 /* FABKitProtocol.h in Headers */,
DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */,
3510FFF91D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */,
+ 3557F7B01E1D27D300CCA5E6 /* MGLDistanceFormatter.h in Headers */,
DA72620B1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */,
404C26E71D89C55D000AA13D /* MGLTileSource_Private.h in Headers */,
DA88485C1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h in Headers */,
@@ -1635,6 +1715,7 @@
DABFB86F1CBE9A0F00D62B32 /* MGLMapView.h in Headers */,
DA6408DC1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */,
353933F31D3FB753003F57D7 /* MGLCircleStyleLayer.h in Headers */,
+ 558DE7A11E5615E400C7916D /* MGLFoundation_Private.h in Headers */,
3538AA1E1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */,
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */,
40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */,
@@ -1644,9 +1725,11 @@
DAF0D8141DFE0EC500B28378 /* MGLVectorSource_Private.h in Headers */,
DABFB8731CBE9A9900D62B32 /* Mapbox.h in Headers */,
357FE2DE1E02D2B20068B753 /* NSCoder+MGLAdditions.h in Headers */,
+ 1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */,
354B83971D2E873E005D9406 /* MGLUserLocationAnnotationView.h in Headers */,
DAF0D8111DFE0EA000B28378 /* MGLRasterSource_Private.h in Headers */,
DABFB86B1CBE99E500D62B32 /* MGLTilePyramidOfflineRegion.h in Headers */,
+ 968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */,
4018B1CB1CDC288E00F666AF /* MGLAnnotationView.h in Headers */,
DABFB85F1CBE99E500D62B32 /* MGLGeometry.h in Headers */,
7E016D851D9E890300A29A21 /* MGLPolygon+MGLAdditions.h in Headers */,
@@ -1839,6 +1922,18 @@
en,
Base,
"zh-Hans",
+ "zh-Hant",
+ de,
+ fr,
+ ja,
+ sv,
+ vi,
+ "pt-BR",
+ es,
+ pl,
+ ru,
+ uk,
+ lt,
);
mainGroup = DA1DC9411CB6C1C2006E619F;
productRefGroup = DA1DC94B1CB6C1C2006E619F /* Products */;
@@ -1871,6 +1966,7 @@
DA821D071CCC6D59007508D4 /* Main.storyboard in Resources */,
DA1DC9731CB6C6CE006E619F /* threestates.geojson in Resources */,
DA821D061CCC6D59007508D4 /* LaunchScreen.storyboard in Resources */,
+ 96E027231E57C76E004B8E66 /* Localizable.strings in Resources */,
DD4823751D94AE6C00EB71B7 /* fill_filter_style.json in Resources */,
DA1DC99F1CB6E088006E619F /* Assets.xcassets in Resources */,
);
@@ -1983,7 +2079,7 @@
DA2E88611CC0382C00F24E7B /* MGLGeometryTests.mm in Sources */,
357579801D501E09000B822E /* MGLFillStyleLayerTests.mm in Sources */,
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
- DA2E88641CC0382C00F24E7B /* MGLOfflineStorageTests.m in Sources */,
+ 3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */,
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
@@ -1999,6 +2095,7 @@
DD58A4C61D822BD000E1F038 /* MGLExpressionTests.mm in Sources */,
3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
+ 55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */,
@@ -2043,6 +2140,7 @@
35136D451D42275100C20EFD /* MGLSymbolStyleLayer.mm in Sources */,
35599DED1D46F14E0048254D /* MGLStyleValue.mm in Sources */,
DA8848211CBAFA6200AB86E3 /* MGLOfflinePack.mm in Sources */,
+ 3557F7B21E1D27D300CCA5E6 /* MGLDistanceFormatter.m in Sources */,
DA8848591CBAFB9800AB86E3 /* MGLMapView.mm in Sources */,
DA8848501CBAFB9800AB86E3 /* MGLAnnotationImage.m in Sources */,
DA8848281CBAFA6200AB86E3 /* MGLShape.mm in Sources */,
@@ -2058,6 +2156,7 @@
DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */,
357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
DA88481C1CBAFA6200AB86E3 /* MGLGeometry.mm in Sources */,
+ 558DE7A21E5615E400C7916D /* MGLFoundation.mm in Sources */,
3510FFF21D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */,
DA88481F1CBAFA6200AB86E3 /* MGLMultiPoint.mm in Sources */,
DA88482B1CBAFA6200AB86E3 /* MGLTypes.m in Sources */,
@@ -2122,6 +2221,7 @@
35599DEE1D46F14E0048254D /* MGLStyleValue.mm in Sources */,
DAA4E42B1CBB730400178DFB /* NSString+MGLAdditions.m in Sources */,
DAA4E4261CBB730400178DFB /* MGLStyle.mm in Sources */,
+ DAA32CC31E4C6B65006F8D24 /* MGLDistanceFormatter.m in Sources */,
DAA4E41D1CBB730400178DFB /* MGLGeometry.mm in Sources */,
DAA4E41F1CBB730400178DFB /* MGLMultiPoint.mm in Sources */,
DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */,
@@ -2135,6 +2235,7 @@
35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */,
357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */,
DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */,
+ 558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */,
3510FFF31D6D9D8C00F413B2 /* NSExpression+MGLAdditions.mm in Sources */,
DAA4E4301CBB730400178DFB /* MGLLocationManager.m in Sources */,
DAA4E4321CBB730400178DFB /* MGLMapView.mm in Sources */,
@@ -2209,11 +2310,43 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
+ 96E027251E57C76E004B8E66 /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 96E027241E57C76E004B8E66 /* Base */,
+ 96E027271E57C77A004B8E66 /* ja */,
+ 96E027281E57C7DB004B8E66 /* zh-Hans */,
+ 96E027291E57C7DE004B8E66 /* zh-Hant */,
+ 96E0272A1E57C7DF004B8E66 /* de */,
+ 96E0272B1E57C7E3004B8E66 /* sv */,
+ 96E0272C1E57C7E5004B8E66 /* fr */,
+ 96E0272D1E57C7E6004B8E66 /* vi */,
+ 96E0272E1E57C7E7004B8E66 /* pt-BR */,
+ 9660916B1E5BBFD700A9A03B /* es */,
+ 9660916C1E5BBFD900A9A03B /* pl */,
+ 9660916D1E5BBFDB00A9A03B /* ru */,
+ 9660916E1E5BBFDC00A9A03B /* uk */,
+ 9660916F1E5BBFDE00A9A03B /* lt */,
+ );
+ name = Localizable.strings;
+ sourceTree = "<group>";
+ };
DA25D5C41CCDA06800607828 /* Root.strings */ = {
isa = PBXVariantGroup;
children = (
DA25D5C51CCDA06800607828 /* Base */,
20DABE8A1DF78149007AC5FF /* zh-Hans */,
+ DAFBD0D41E3FA7A2000CD6BF /* zh-Hant */,
+ DAA32CA51E4C450F006F8D24 /* de */,
+ DAA32CB11E4C4C8A006F8D24 /* fr */,
+ DAA32CB81E4C4EE6006F8D24 /* sv */,
+ DAA32CBE1E4C4F71006F8D24 /* vi */,
+ DA9C012E1E4C7B6100C4742A /* pt-BR */,
+ DA737ADC1E59145700AD2CDE /* es */,
+ DA737AE11E59157600AD2CDE /* pl */,
+ DA737AE61E59171700AD2CDE /* ru */,
+ DA737AEA1E5917EF00AD2CDE /* uk */,
+ DA1AC01C1E5B87EC006DF1D6 /* lt */,
);
name = Root.strings;
sourceTree = "<group>";
@@ -2223,6 +2356,17 @@
children = (
DA8933A01CCC951200E68420 /* Base */,
20DABE881DF78148007AC5FF /* zh-Hans */,
+ DAFBD0D31E3FA7A1000CD6BF /* zh-Hant */,
+ DAA32CA41E4C4502006F8D24 /* de */,
+ DAA32CAC1E4C4971006F8D24 /* fr */,
+ DAA32CB71E4C4ED8006F8D24 /* sv */,
+ DAA32CBC1E4C4F5D006F8D24 /* vi */,
+ DA9C012D1E4C7B1F00C4742A /* pt-BR */,
+ 968F36B41E4D0FC6003A5522 /* ja */,
+ DA737ADB1E5913BA00AD2CDE /* es */,
+ DA737AE71E59172C00AD2CDE /* ru */,
+ DA737AE91E5917C300AD2CDE /* uk */,
+ DA1AC01B1E5B8774006DF1D6 /* lt */,
);
name = Localizable.strings;
sourceTree = "<group>";
@@ -2232,6 +2376,11 @@
children = (
DA8933BB1CCD2CA100E68420 /* Base */,
20DABE861DF78148007AC5FF /* zh-Hans */,
+ DAFBD0D21E3FA7A1000CD6BF /* zh-Hant */,
+ DAA32CA31E4C44F1006F8D24 /* de */,
+ DAA32CB51E4C4CF4006F8D24 /* ja */,
+ DAA32CBD1E4C4F62006F8D24 /* vi */,
+ DA6023F11E4CE94300DBFF23 /* sv */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -2240,6 +2389,14 @@
isa = PBXVariantGroup;
children = (
DA8933BE1CCD2CAD00E68420 /* en */,
+ DAA32CA11E4C44DB006F8D24 /* de */,
+ DAA32CAB1E4C491A006F8D24 /* fr */,
+ DA9C012C1E4C7ADB00C4742A /* pt-BR */,
+ DA6023F21E4CE94800DBFF23 /* sv */,
+ DA737ADA1E59139D00AD2CDE /* es */,
+ DA737AE01E59150A00AD2CDE /* pl */,
+ DA737AE51E5916D400AD2CDE /* ru */,
+ DA1AC0201E5B8917006DF1D6 /* uk */,
);
name = Foundation.stringsdict;
sourceTree = "<group>";
@@ -2256,6 +2413,9 @@
isa = PBXVariantGroup;
children = (
DAC49C621CD07D74009E1AA3 /* en */,
+ DAA32CA21E4C44DD006F8D24 /* de */,
+ DAA32CA91E4C4919006F8D24 /* fr */,
+ DA9C012B1E4C7AD900C4742A /* pt-BR */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
@@ -2306,7 +2466,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -2352,7 +2512,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 7.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SYMROOT = ../../build/ios;
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
index 437f000a3c..40249b8024 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/CI.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
index 0a12923924..9dd128ff24 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme
index 2bba3a3e05..8e1c176bba 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic+static.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
index 31c86be795..7dfffccef5 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
index a299ab49b1..f1227ac139 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/iosapp.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/static.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/static.xcscheme
index 9bfc8aac36..156651a4a6 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/static.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/static.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0810"
+ LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index a038008dd3..9beeb1ddc4 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -23,6 +23,7 @@ custom_categories:
- Working with GeoJSON Data
- For Style Authors
- Info.plist Keys
+ - Gesture Recognizers
- name: Maps
children:
- MGLAccountManager
@@ -117,3 +118,4 @@ custom_categories:
- MGLClockDirectionFormatter
- MGLCompassDirectionFormatter
- MGLCoordinateFormatter
+ - MGLDistanceFormatter
diff --git a/platform/ios/resources/de.lproj/Localizable.strings b/platform/ios/resources/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..1ea03e7d61
--- /dev/null
+++ b/platform/ios/resources/de.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Mehr Infos anzeigen";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "Der Data-Task der Sitzung ist fehlgeschlagen. Die ursprüngliche Anfrage war: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Der Statuscode ist %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Abbrechen";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Dreht die Karte nach Norden";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Kompass";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Um hier eine von Mapbox-Karte anzuzeigen, muss das Zugriffs-Token als %1$@ in %2$@ eingetragen werden.\n\nFür detaillierte Informationen, siehe:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Zeigt Danksagunen, ein Kontakformular und mehr an";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Über diese Karte";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Karte";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoomstufe %1$d\n%2$ld Anmerkung(en) sichtbar";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Durch anonymisierte Nutzungsdaten können Sie helfen, OpenStreetMap- und Mapbox-Karten zu verbessern.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Nicht teilnehmen";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Teilnehmen";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Durch anonymisierte Nutzungsdaten helfen Sie, OpenStreetMap- und Mapbox-Karten zu verbessern.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Teilnahme beenden";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Weiterhin teilnehmen";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Mehr Informationen";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapbox-Telemetrie";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Mapbox-Karten verbessern";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Sie sind hier";
+
diff --git a/platform/ios/resources/de.lproj/Localizable.stringsdict b/platform/ios/resources/de.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..a41ddac14e
--- /dev/null
+++ b/platform/ios/resources/de.lproj/Localizable.stringsdict
@@ -0,0 +1,23 @@
+<?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>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>Zoomstufe %d
+%#@count@ sichtbar</string>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>%d Anmerkung</string>
+ <key>other</key>
+ <string>%d Anmerkungen</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/es.lproj/Localizable.strings b/platform/ios/resources/es.lproj/Localizable.strings
new file mode 100644
index 0000000000..88a7d8b42f
--- /dev/null
+++ b/platform/ios/resources/es.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Muestra más información";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "Error en la tarea de datos de sesión. La solicitud original fue: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "El código de estado fue %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Cancelar";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Gira el mapa para hacer frente al norte";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Brújula";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Para mostrar un mapa alojado en Mapbox aquí, establezca %1$@ con su token de acceso en %2$@\n\nPara obtener instrucciones detalladas, consulte:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Muestra créditos, un formulario de comentarios y más";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Acerca de este mapa";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Mapa";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Ayudas a mejorar los mapas de OpenStreetMap y Mapbox al aportar datos de uso anónimos.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "No participar";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Participar";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Ayudas a mejorar los mapas de OpenStreetMap y Mapbox al aportar datos de uso anónimos.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Dejar de participar";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Seguir participando";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Cuéntame más";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Telemetría Mapbox";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Mejorar los mapas de Mapbox";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Usted está aquí";
+
diff --git a/platform/ios/resources/fr.lproj/Localizable.strings b/platform/ios/resources/fr.lproj/Localizable.strings
new file mode 100644
index 0000000000..075042c695
--- /dev/null
+++ b/platform/ios/resources/fr.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Voir plus d’informations";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "La tâche de données pour cette session a échouée. Requête originale : %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Le code d’erreur était %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Annuler";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Tourne la carte vers le nord";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Boussole";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Pour afficher une carte hébergée par Mapbox, remplacez %1$@ par votre token d’accès dans %2$@\n\nPour plus d’informations, voir :";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Montre les crédits, un formulaire de retour d’expérience, et plus.";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "À propos de cette carte";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Carte";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible(s)";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Vous pouvez contribuer à OpenStreetMap et Mapbox en partageant des données d’utilisation anonymes.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Ne pas participer";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Participer";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Vous aidez à améliorer OpenStreetMap et Mapbox en partageant des données d’utilisation anonymes.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Ne plus participer";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Continuer à participer";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "En savoir plus";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Télémétrie Mapbox";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Améliorez les cartes Mapbox";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Vous êtes ici";
+
diff --git a/platform/ios/resources/fr.lproj/Localizable.stringsdict b/platform/ios/resources/fr.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..76a698053f
--- /dev/null
+++ b/platform/ios/resources/fr.lproj/Localizable.stringsdict
@@ -0,0 +1,23 @@
+<?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>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>Zoom %dx
+%#@count@</string>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>%d annotation visible</string>
+ <key>other</key>
+ <string>%d annotations visibles</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/ja.lproj/Localizable.strings b/platform/ios/resources/ja.lproj/Localizable.strings
new file mode 100644
index 0000000000..87c40bb920
--- /dev/null
+++ b/platform/ios/resources/ja.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "詳細を伝える";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "The status code was %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "キャンセル";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "地図を真北に回転させる";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "磁針";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "北";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "To display a Mapbox-hosted map here, set %1$@ to your access token in %2$@\n\nFor detailed instructions, see:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Shows credits, a feedback form, and more";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "この地図について";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "地図";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "ズーム %1$d倍\n%2$ld ピン現れる";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "参加しない";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "参加する";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "参加をやめる";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "参加を続ける";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "詳細";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapboxテレメトリー";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Mapboxの地図を改善する";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "現在位置";
+
diff --git a/platform/ios/resources/lt.lproj/Localizable.strings b/platform/ios/resources/lt.lproj/Localizable.strings
new file mode 100644
index 0000000000..d160895ea6
--- /dev/null
+++ b/platform/ios/resources/lt.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Rodo daugiau informacijos";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "Užklausa nepavyko. Pradinė užklausa buvo: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Būklės kodas: %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Atšaukti";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Pasuka žemėlapį šiaure į viršų";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Kompasas";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "Š";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Nustatykite %1$@ kaip jūsų prieigos raktą %2$@ byloje tam, kad atvaizduoti žemėlapį patalpintą Mapbox.\n\nDaugiau informacijos:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Rodo kūrėjų sąrašą, grįžtamo ryšio formą ir daugiau.";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Apie šį žemėlapį";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Žemėlapis";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Priartinimas: %1$dx\nMatomos anotacijos: %2$ld ";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Padėkite padaryti OpenStreetMap ir Mapbox žemėlapius geresniais dalindamiesi anoniminiais naudojimosi duomenimis.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Nesidalinti";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Dalintis";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Jūs padedate padaryti OpenStreetMap ir Mapbox žemėlapius geresniais dalindamiesi anoniminiais naudojimosi duomenimis.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Stabdyti dalinimąsi";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Tęsti dalinimąsi";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Daugiau informacijos";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapbox Telemetrija";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Padaryti Mapbox žemėlapius geresniais";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Jūs esate čia";
+
diff --git a/platform/ios/resources/pt-BR.lproj/Localizable.strings b/platform/ios/resources/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000000..56eaa7cf9f
--- /dev/null
+++ b/platform/ios/resources/pt-BR.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Mostrar mais informações";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "O código de status foi %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Cancelar";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Rotaciona o mapa com face ao norte";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Compasso";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "To display a Mapbox-hosted map here, set %1$@ to your access token in %2$@\n\nFor detailed instructions, see:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Mostra os créditos, um formulário de avaliação, e mais";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Sobre este mapa";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Mapa";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld anotações visíveis";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Não Participar";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Participar";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Parar de Participar";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Continuar Participando";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Me Diga Mais";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Telemetria do Mapbox";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Melhorar os Mapas do Mapbox";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Você Está Aqui";
+
diff --git a/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict b/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict
new file mode 100644
index 0000000000..2b4bf30cba
--- /dev/null
+++ b/platform/ios/resources/pt-BR.lproj/Localizable.stringsdict
@@ -0,0 +1,23 @@
+<?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>MAP_A11Y_VALUE</key>
+ <dict>
+ <key>NSStringLocalizedFormatKey</key>
+ <string>Zoom %dx
+%#@count@</string>
+ <key>count</key>
+ <dict>
+ <key>NSStringFormatSpecTypeKey</key>
+ <string>NSStringPluralRuleType</string>
+ <key>NSStringFormatValueTypeKey</key>
+ <string>ld</string>
+ <key>one</key>
+ <string>%d anotação visível</string>
+ <key>other</key>
+ <string>%d anotações visíveis</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/platform/ios/resources/ru.lproj/Localizable.strings b/platform/ios/resources/ru.lproj/Localizable.strings
new file mode 100644
index 0000000000..c895e34cee
--- /dev/null
+++ b/platform/ios/resources/ru.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Показать больше информации";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "The status code was %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Отмена";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Повернуть карту на север";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Компас";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "To display a Mapbox-hosted map here, set %1$@ to your access token in %2$@\n\nFor detailed instructions, see:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Показать авторство, форму обратной связи и многое другое";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Об этой карте";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Карта";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Не участвовать";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Участвовать";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Прекратить участие";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Продолжить участие";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Узнать больше";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapbox телеметрия";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Сделать карты Mapbox лучше";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Вы здесь";
+
diff --git a/platform/ios/resources/sv.lproj/Localizable.strings b/platform/ios/resources/sv.lproj/Localizable.strings
new file mode 100644
index 0000000000..1f1aac2d78
--- /dev/null
+++ b/platform/ios/resources/sv.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Visa mer information";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "Sessionens anrop misslyckades. Originalanropet var: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Statuskoden var %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Avbryt";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Roterar kartan mot norr";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Kompass";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "N";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Sätt %1$@ till din access token i %2$@ för att visa kartan som Mapbox levererar.";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Visa medverkande, återkopplingsformulär och mer.";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Om den här kartan";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Karta";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Du kan hjälpa till att göra OpenStreetMap och Mapbox karttjänster bättre genom att bidra med anonymiserad användningsdata.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Avstå";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Delta";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Du hjälper till att göra OpenStreetMap och Mapbox karttjänster bättre genom att bidra med anonymiserad användningsdata.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Avsluta deltagandet";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Fortsätt deltagandet";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Visa mer";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapbox Telemetri";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Gör Mapbox kartor bättre";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Där är här";
+
diff --git a/platform/ios/resources/uk.lproj/Localizable.strings b/platform/ios/resources/uk.lproj/Localizable.strings
new file mode 100644
index 0000000000..86873c69c0
--- /dev/null
+++ b/platform/ios/resources/uk.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Показує більше інформації";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Код стану %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Скасувати";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Обертає напрямок мапи на північ";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "Компас";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "Пн";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Щоб побачити мапу з серверів Mapbox тут, вкажіть у %1$@ ваш ключ доступу для %2$@\n\nДля отримання докладих інструкцій, дивіться:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Показує інформацію про розробників, форму зворотнього зв'язку та інше";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Про мапу";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Мапа";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Ви можете допомогти зробити мапи OpenStreetMap та Mapbox кращими надаючі анонімізовані дані про користування застосунком.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Відмовитись";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Брати участь";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Ви допомагаєте робити мапи OpenStreetMap та Mapbox кращими надаючі анонімізовані дані про користування застосунком.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Припинити участь";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Продовжити участь";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Докладніше";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Телеметрія Mapbox";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Робить мапи Mapbox кращими";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Ви тут";
+
diff --git a/platform/ios/resources/vi.lproj/Localizable.strings b/platform/ios/resources/vi.lproj/Localizable.strings
new file mode 100644
index 0000000000..c730ea71c7
--- /dev/null
+++ b/platform/ios/resources/vi.lproj/Localizable.strings
@@ -0,0 +1,75 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "Hiển thị thêm thông tin";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "Tác vụ lấy dữ liệu của phiên làm việc bị thất bại. Yêu cầu ban đầu là: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "Mã trạng thái là %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "Hủy bỏ";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "Quay bản đồ về hướng bắc";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "La bàn";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "B";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "Để hiển thị bản đồ do Mapbox phục vụ tại đây, đặt %1$@ là dấu hiệu truy cập của bạn trong %2$@\n\nXem hướng dẫn chi tiết tại:";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "Hiển thị lời ghi công, biểu mẫu phản hồi, và thêm nữa";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "Giới thiệu về bản đồ này";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "Bản đồ";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "Thu phóng gấp %1$d lần\n%2$ld chú thích đang xuất hiện";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "Hãy giúp cải tiến các bản đồ OpenStreetMap và Mapbox bằng cách đóng góp dữ liệu vô danh hóa về cách sử dụng.";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "Không Tham gia";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "Tham gia";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "Bạn đang giúp cải tiến các bản đồ OpenStreetMap và Mapbox bằng cách đóng góp dữ liệu vô danh hóa về cách sử dụng.";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "Ngừng Tham gia";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "Tiếp tục Tham gia";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "Tìm hiểu Thêm";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Trình viễn trắc Mapbox";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "Cải tiến các Bản đồ Mapbox";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "Bạn ở Đây";
+
diff --git a/platform/ios/resources/zh-Hant.lproj/Localizable.strings b/platform/ios/resources/zh-Hant.lproj/Localizable.strings
new file mode 100644
index 0000000000..1b4e7416d9
--- /dev/null
+++ b/platform/ios/resources/zh-Hant.lproj/Localizable.strings
@@ -0,0 +1,84 @@
+/* Accessibility hint */
+"ANNOTATION_A11Y_HINT" = "顯示信息";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
+
+/* No comment provided by engineer. */
+"API_CLIENT_400_REASON" = "The status code was %ld";
+
+/* No comment provided by engineer. */
+"CANCEL" = "取消";
+
+/* Accessibility hint */
+"COMPASS_A11Y_HINT" = "旋轉地圖使正北朝上";
+
+/* Accessibility label */
+"COMPASS_A11Y_LABEL" = "指南針";
+
+/* Compass abbreviation for north */
+"COMPASS_NORTH" = "北";
+
+/* Copyright notice in attribution sheet */
+"COPY_MAPBOX" = "© Mapbox";
+
+/* Copyright notice in attribution sheet */
+"COPY_OSM" = "© OpenStreetMap";
+
+/* Instructions in Interface Builder designable; {key}, {plist file name} */
+"DESIGNABLE" = "在%2$@中將你的access token設爲%1$@可在這裏顯示Mapbox上的地圖\n\n更多說明請見";
+
+/* Setup documentation URL display string; keep as short as possible */
+"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
+
+/* Accessibility hint */
+"INFO_A11Y_HINT" = "顯示致謝、用戶反饋及更多";
+
+/* Accessibility label */
+"INFO_A11Y_LABEL" = "關於這個地圖";
+
+/* Accessibility label */
+"LOGO_A11Y_LABEL" = "Mapbox";
+
+/* Accessibility label */
+"MAP_A11Y_LABEL" = "地圖";
+
+/* Map accessibility value */
+"MAP_A11Y_VALUE" = "地圖縮放%1$d倍\n有%2$ld處標記可見";
+
+/* Action in attribution sheet */
+"MAP_FEEDBACK" = "改進地圖";
+
+/* Action sheet title */
+"SDK_NAME" = "Mapbox iOS SDK";
+
+/* Telemetry prompt message */
+"TELEMETRY_DISABLED_MSG" = "你可以提供匿名數據來幫助OpenStreetMap和Mapbox的地圖變得更好。";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_OFF" = "暫不參與";
+
+/* Telemetry prompt button */
+"TELEMETRY_DISABLED_ON" = "我要參與";
+
+/* Telemetry prompt message */
+"TELEMETRY_ENABLED_MSG" = "你的匿名數據在幫助OpenStreetMap和Mapbox的地圖變得更好。";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_OFF" = "不再參與";
+
+/* Telemetry prompt button */
+"TELEMETRY_ENABLED_ON" = "繼續參與";
+
+/* Telemetry prompt button */
+"TELEMETRY_MORE" = "詳細信息";
+
+/* Action in attribution sheet */
+"TELEMETRY_NAME" = "Mapbox傳感數據";
+
+/* Telemetry prompt title */
+"TELEMETRY_TITLE" = "讓Mapbox地圖變得更好";
+
+/* Default user location annotation title */
+"USER_DOT_TITLE" = "你在這裏";
+
diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh
index 2265afdba6..479803aa05 100755
--- a/platform/ios/scripts/deploy-packages.sh
+++ b/platform/ios/scripts/deploy-packages.sh
@@ -9,7 +9,7 @@ set -u
# GITHUB_RELEASE=true: Upload to github
# BINARY_DIRECTORY=build/ios/deploy: Directory in which to save test packages
-# environment variables and dependencies:
+# environment variables and dependencies:
# - You must run "mbx auth ..." before running
# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
# - "wget" is required for downloading the zip files from s3
@@ -20,21 +20,21 @@ function finish { >&2 echo -en "\033[0m"; }
trap finish EXIT
buildPackageStyle() {
- local package=$1 style=""
+ local package=$1 style=""
if [[ ${#} -eq 2 ]]; then
style="$2"
- fi
+ fi
step "Building: make ${package} ${style}"
make ${package}
step "Publishing ${package} with ${style}"
local file_name=""
- if [ -z ${style} ]
+ if [ -z ${style} ]
then
./platform/ios/scripts/publish.sh "${PUBLISH_VERSION}"
- file_name=mapbox-ios-sdk-${PUBLISH_VERSION}.zip
+ file_name=mapbox-ios-sdk-${PUBLISH_VERSION}.zip
else
./platform/ios/scripts/publish.sh "${PUBLISH_VERSION}" ${style}
- file_name=mapbox-ios-sdk-${PUBLISH_VERSION}-${style}.zip
+ file_name=mapbox-ios-sdk-${PUBLISH_VERSION}-${style}.zip
fi
step "Downloading ${file_name} from s3 to ${BINARY_DIRECTORY}"
wget -O ${BINARY_DIRECTORY}/${file_name} http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/${file_name}
diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh
index 796de17146..e4403c4652 100755
--- a/platform/ios/scripts/package.sh
+++ b/platform/ios/scripts/package.sh
@@ -117,8 +117,8 @@ if [[ ${BUILD_FOR_DEVICE} == true ]]; then
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphoneos/lib} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a`
-
+ `cmake -LA -N ${DERIVED_DATA} | grep MASON_PACKAGE_icu_LIBRARIES | cut -d= -f2`
+
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphoneos/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
@@ -157,8 +157,8 @@ else
libtool -static -no_warning_for_no_symbols \
-o ${OUTPUT}/static/${NAME}.framework/${NAME} \
${LIBS[@]/#/${PRODUCTS}/${BUILDTYPE}-iphonesimulator/lib} \
- `find mason_packages/ios-${IOS_SDK_VERSION} -type f -name libgeojson.a`
-
+ `cmake -LA -N ${DERIVED_DATA} | grep MASON_PACKAGE_icu_LIBRARIES | cut -d= -f2`
+
cp -rv ${PRODUCTS}/${BUILDTYPE}-iphonesimulator/${NAME}.bundle ${STATIC_BUNDLE_DIR}
fi
@@ -222,7 +222,7 @@ function create_podspec {
if [[ ${1} == "static" ]]; then
awk '/Pod::Spec.new/,/m.platform/' ${INPUT_PODSPEC} > ${OUTPUT_PODSPEC}
cat platform/ios/${NAME}-iOS-SDK-static-part.podspec >> ${OUTPUT_PODSPEC}
- sed -i '' "s/.*:http.*/${POD_SOURCE_PATH}/" ${OUTPUT_PODSPEC}
+ sed -i '' "s/.*:http.*/${POD_SOURCE_PATH}/" ${OUTPUT_PODSPEC}
fi
cp -pv LICENSE.md ${OUTPUT}/${1}/
}
diff --git a/platform/ios/scripts/release-fabric.sh b/platform/ios/scripts/release-fabric.sh
index 6f05e2886e..a523705b7b 100755
--- a/platform/ios/scripts/release-fabric.sh
+++ b/platform/ios/scripts/release-fabric.sh
@@ -15,7 +15,7 @@ echo "Downloading ${FILE_NAME}:"
wget -P ${BINARY_DIRECTORY} http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/${FILE_NAME}
echo "Extracting ${ZIP_ARCHIVE_PATH} to ${BINARY_DIRECTORY}/${ZIP_OUTPUT}"
-unzip -q ${ZIP_ARCHIVE_PATH} -d ${BINARY_DIRECTORY}/${ZIP_OUTPUT}
+unzip -q ${ZIP_ARCHIVE_PATH} -d ${BINARY_DIRECTORY}/${ZIP_OUTPUT}
ditto ${BINARY_DIRECTORY}/${ZIP_OUTPUT}/static/Mapbox.framework ${BINARY_DIRECTORY}/Mapbox.framework
echo "Zipping framework:"
@@ -25,7 +25,7 @@ cd $OLDPWD
echo "Validating framework:"
./validate-fabric-zip.sh ${BINARY_DIRECTORY}/Mapbox.framework.zip
-
+
echo "Uploading ${BINARY_DIRECTORY}/Mapbox.framework.zip to https://kits.fabric.io/manage-api/v1/kit-releases/ios/$BUNDLE_ID/$PUBLISH_VERSION with key ${FABRIC_KIT_API_KEY}"
curl --fail -v -X PUT -H "X-FabricKits-ApiKey: ${FABRIC_KIT_API_KEY}" \
-F "release_artifact=@${BINARY_DIRECTORY}/Mapbox.framework.zip;type=application/octet-stream" \
diff --git a/platform/ios/scripts/validate-fabric-zip.sh b/platform/ios/scripts/validate-fabric-zip.sh
index 7cc772d70c..2cd1e90ee7 100755
--- a/platform/ios/scripts/validate-fabric-zip.sh
+++ b/platform/ios/scripts/validate-fabric-zip.sh
@@ -12,7 +12,7 @@ set -e
if [ ! -f "$1" ]; then
printf "No file found at ${1}\n"
- printf "Usage: $ ./validate_zip.sh <path to zip>\n"; exit 1;
+ printf "Usage: $ ./validate_zip.sh <path to zip>\n"; exit 1;
fi
function verifyFramework() {
@@ -32,14 +32,14 @@ function verifyFramework() {
printf "$FRAMEWORK_NAME contains modulemap: ✓\n"
# Verify there is a modulemap so Swift can use the framework
- if grep -q "link" "$MODULE_MAP"; then
+ if grep -q "link" "$MODULE_MAP"; then
printf "$FRAMEWORK_NAME modulemap contains dependent system frameworks ✓\n"
else
printf "Warning: ${FRAMEWORK_NAME} does not list any system library dependencies. Double check all dependent frameworks and libraries are listed. \n";
fi
# Verify there is at least one header listed in the module map
- if grep -q ".*.h" "$MODULE_MAP"; then
+ if grep -q ".*.h" "$MODULE_MAP"; then
printf "$FRAMEWORK_NAME modulemap contains headers ✓\n";
else
printf "Error: ${FRAMEWORK_NAME} does not list any headers in the modulemap\n";
@@ -47,7 +47,7 @@ function verifyFramework() {
fi
# Verify there is at least a headers folder
- if [[ ! -d "$HEADER_PATH" ]]; then
+ if [[ ! -d "$HEADER_PATH" ]]; then
printf "ERROR: Headers not not found in ${FRAMEWORK_NAME}\n";
exit 5;
fi
@@ -55,7 +55,7 @@ function verifyFramework() {
# Verify the static lib at least has simulator and the two common ARM architectures
local PRESENT_ARCHITECTURES=$( xcrun lipo -info "${BINARY_PATH}" )
for arch in "armv7" "arm64" "i386" "x86_64"; do
- if [[ ! $PRESENT_ARCHITECTURES == *$arch* ]]; then
+ if [[ ! $PRESENT_ARCHITECTURES == *$arch* ]]; then
printf "ERROR: Architecture ${arch} not found in ${FRAMEWORK_NAME}\n";
exit 6;
fi
@@ -69,7 +69,7 @@ function verifyFramework() {
if [[ ! $SYMBOLS == *"LLVM"* ]]; then
printf "ERROR: Bitcode segments not found in ${FRAMEWORK_NAME}. Users will fail to archive their builds \n";
exit 7;
- fi
+ fi
done
printf "$FRAMEWORK_NAME contains bitcode: ✓\n"
@@ -82,19 +82,19 @@ function verifyFramework() {
printf "$FRAMEWORK_NAME contains Info.plist: ✓\n"
# Verify there is a bundle identifier in Info.plist
- # And verify it does not contain any vestigial string templating
+ # And verify it does not contain any vestigial string templating
local BUNDLE_NAME=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "${PLIST_PATH}")
if [[ -z "$BUNDLE_NAME" ]]; then
printf "ERROR: Info.plist not found in $FRAMEWORK_NAME or CFBundleIdentifier not set\n";
exit 9;
- elif [[ "$BUNDLE_NAME" == *"$"* ]]; then
+ elif [[ "$BUNDLE_NAME" == *"$"* ]]; then
printf "ERROR: CFBundleIdentifier is invalid: $BUNDLE_NAME\n";
exit 10;
else
printf "$FRAMEWORK_NAME has bundle: $BUNDLE_NAME ✓\n"
fi
- # Verify there is a bundle version in the Info.plist
+ # Verify there is a bundle version in the Info.plist
local BUNDLE_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" "${PLIST_PATH}")
if [[ -z "$BUNDLE_VERSION" ]]; then
printf "ERROR: No CFBundleShortVersionString found in $FRAMEWORK_NAME\n";
@@ -119,7 +119,7 @@ printf "Scanning for frameworks...\n"
FRAMEWORKS=( $(find "$TEMP_DIR" -name "*.framework" -maxdepth 1) )
if [ -z "$FRAMEWORKS" ]; then
printf "ERROR: No frameworks found at the top level within the zip archive.";
- exit 2;
+ exit 2;
fi
# Verify each framework found individually
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m
index 5e8ee5fe1d..22ee5c55f5 100644
--- a/platform/ios/src/MGLAPIClient.m
+++ b/platform/ios/src/MGLAPIClient.m
@@ -75,22 +75,22 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
[request setValue:self.userAgent forHTTPHeaderField:MGLAPIClientHeaderFieldUserAgentKey];
[request setValue:MGLAPIClientHeaderFieldContentTypeValue forHTTPHeaderField:MGLAPIClientHeaderFieldContentTypeKey];
[request setHTTPMethod:MGLAPIClientHTTPMethodPost];
-
+
NSData *jsonData = [self serializedDataForEvents:events];
-
+
// Compressing less than 3 events can have a negative impact on the size.
if (events.count > 2) {
NSData *compressedData = [jsonData mgl_compressedData];
[request setValue:@"deflate" forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey];
[request setHTTPBody:compressedData];
}
-
+
// Set JSON data if events.count were less than 3 or something went wrong with compressing HTTP body data.
if (!request.HTTPBody) {
[request setValue:nil forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey];
[request setHTTPBody:jsonData];
}
-
+
return [request copy];
}
@@ -143,10 +143,10 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
-
+
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
SecTrustResultType trustResult;
-
+
// Validate the certificate chain with the device's trust store anyway
// This *might* give use revocation checking
SecTrustEvaluate(serverTrust, &trustResult);
@@ -154,13 +154,13 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
{
// Look for a pinned certificate in the server's certificate chain
long numKeys = SecTrustGetCertificateCount(serverTrust);
-
+
BOOL found = NO;
// Try GeoTrust Cert First
for (int lc = 0; lc < numKeys; lc++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
-
+
// Compare Remote Key With Local Version
if ([remoteCertificateData isEqualToData:_geoTrustCert]) {
// Found the certificate; continue connecting
@@ -169,13 +169,13 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
break;
}
}
-
+
if (!found) {
// Fallback to Digicert Cert
for (int lc = 0; lc < numKeys; lc++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
-
+
// Compare Remote Key With Local Version
if ([remoteCertificateData isEqualToData:_digicertCert]) {
// Found the certificate; continue connecting
@@ -184,13 +184,13 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
break;
}
}
-
+
if (!found && _usesTestServer) {
// See if this is test server
for (int lc = 0; lc < numKeys; lc++) {
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
-
+
// Compare Remote Key With Local Version
if ([remoteCertificateData isEqualToData:_testServerCert]) {
// Found the certificate; continue connecting
@@ -200,7 +200,7 @@ static NSString * const MGLAPIClientHTTPMethodPost = @"POST";
}
}
}
-
+
if (!found) {
// The certificate wasn't found in GeoTrust nor Digicert. Cancel the connection.
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
diff --git a/platform/ios/src/MGLAnnotationImage.h b/platform/ios/src/MGLAnnotationImage.h
index 95bce21f51..fbeee18624 100644
--- a/platform/ios/src/MGLAnnotationImage.h
+++ b/platform/ios/src/MGLAnnotationImage.h
@@ -14,7 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Initializes and returns a new annotation image object.
-
+
@param image The image to be displayed for the annotation.
@param reuseIdentifier The string that identifies that this annotation image is
reusable.
@@ -30,11 +30,11 @@ NS_ASSUME_NONNULL_BEGIN
/**
The string that identifies that this annotation image is reusable. (read-only)
-
+
You specify the reuse identifier when you create the image object. You use this
type later to retrieve an annotation image object that was created previously
but which is currently unused because its annotation is not on screen.
-
+
If you define distinctly different types of annotations (with distinctly
different annotation images to go with them), you can differentiate between the
annotation types by specifying different reuse identifiers for each one.
@@ -43,8 +43,8 @@ NS_ASSUME_NONNULL_BEGIN
/**
A Boolean value indicating whether the annotation is enabled.
-
- The default value of this property is `YES`. If the value of this property is
+
+ The default value of this property is `YES`. If the value of this property is
`NO`, the annotation image ignores touch events and cannot be selected.
*/
@property (nonatomic, getter=isEnabled) BOOL enabled;
diff --git a/platform/ios/src/MGLAnnotationImage.m b/platform/ios/src/MGLAnnotationImage.m
index 9c9c175ab9..3b89b19bd8 100644
--- a/platform/ios/src/MGLAnnotationImage.m
+++ b/platform/ios/src/MGLAnnotationImage.m
@@ -52,9 +52,9 @@
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO;
-
+
MGLAnnotationImage *otherAnnotationImage = other;
-
+
return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier)
|| [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier])
&& _enabled == otherAnnotationImage.enabled
diff --git a/platform/ios/src/MGLAnnotationView.h b/platform/ios/src/MGLAnnotationView.h
index d159976a4c..532483350a 100644
--- a/platform/ios/src/MGLAnnotationView.h
+++ b/platform/ios/src/MGLAnnotationView.h
@@ -12,7 +12,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
MGLAnnotationViewDragStateNone = 0,
/**
An action occurred that indicated the view should begin dragging.
-
+
The map view automatically moves draggable annotation views to this state
in response to the dragging the view after pressing and holding on it.
*/
@@ -29,7 +29,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
MGLAnnotationViewDragStateCanceling,
/**
An action occurred that indicated the view was dropped by the user.
-
+
The map view automatically moves annotation views to this state in response
to the user lifting their finger at the end of a drag gesture.
*/
@@ -44,7 +44,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
delegate to a corresponding annotation view. If an annotation view is created
with a reuse identifier, the map view may recycle the view when it goes
offscreen.
-
+
Annotation views are compatible with UIKit, Core Animation, and other Cocoa
Touch frameworks. On the other hand, if you do not need animation or
interactivity such as dragging, you can use an `MGLAnnotationImage` instead to
@@ -56,14 +56,14 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
Initializes and returns a new annotation view object.
-
+
The reuse identifier provides a way for you to improve performance by recycling
annotation views as they enter and leave the map’s viewport. As an annotation
leaves the viewport, the map view moves its associated view to a reuse queue.
When a new annotation becomes visible, you can request a view for that
annotation by passing the appropriate reuse identifier string to the
`-[MGLMapView dequeueReusableAnnotationViewWithIdentifier:]` method.
-
+
@param reuseIdentifier A unique string identifier for this view that allows you
to reuse this view with multiple similar annotations. You can set this
parameter to `nil` if you don’t intend to reuse the view, but it is a good
@@ -75,7 +75,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
Called when the view is removed from the reuse queue.
-
+
The default implementation of this method does nothing. You can override it in
your custom annotation view implementation to put the view in a known state
before it is returned to your map view delegate.
@@ -84,7 +84,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
The annotation object currently associated with the view.
-
+
You should not change the value of this property directly. This property
contains a non-`nil` value while the annotation view is visible on the map. If
the view is queued, waiting to be reused, the value is `nil`.
@@ -93,11 +93,11 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
The string that identifies that this annotation view is reusable.
-
+
You specify the reuse identifier when you create the view. You use the
identifier later to retrieve an annotation view that was created previously but
which is currently unused because its annotation is not on-screen.
-
+
If you define distinctly different types of annotations (with distinctly
different annotation views to go with them), you can differentiate between the
annotation types by specifying different reuse identifiers for each one.
@@ -108,14 +108,14 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
The offset, measured in points, at which to place the center of the view.
-
+
By default, the center point of an annotation view is placed at the geographic
coordinate point of the associated annotation. If you do not want the view to
be centered, you can use this property to reposition the view. The offset’s
`dx` and `dy` values are measured in points. Positive offset values move the
annotation view down and to the right, while negative values move it up and to
the left.
-
+
Set the offset if the annotation view’s visual center point is somewhere other
than the logical center of the view. For example, the view may contain an image
that depicts a downward-pointing pushpin or thumbtack, with the tip positioned
@@ -128,14 +128,14 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
A Boolean value that determines whether the annotation view grows and shrinks
as the distance between the viewpoint and the annotation view changes on a
tilted map.
-
+
When the value of this property is `YES` and the map is tilted, the annotation
view appears smaller if it is towards the top of the view (closer to the
horizon) and larger if it is towards the bottom of the view (closer to the
viewpoint). This is also the behavior of `MGLAnnotationImage` objects. When the
value of this property is `NO` or the map’s pitch is zero, the annotation view
remains the same size regardless of its position on-screen.
-
+
The default value of this property is `YES`. Set this property to `NO` if the
view’s legibility is important.
*/
@@ -145,15 +145,15 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
A Boolean value indicating whether the annotation view is currently selected.
-
+
You should not set the value of this property directly. If the property is set
to `YES`, the annotation view is displaying a callout.
-
+
By default, this property is set to `NO` and becomes `YES` when the user taps
the view. Selecting another annotation, whether it is associated with an
`MGLAnnotationView` or `MGLAnnotationImage` object, deselects any currently
selected view.
-
+
Setting this property changes the view’s appearance to reflect the new value
immediately. If you want the change to be animated, use the
`-setSelected:animated:` method instead.
@@ -162,12 +162,12 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
Sets the selection state of the annotation view with an optional animation.
-
+
You should not call this method directly. A map view calls this method in
response to user interactions with the annotation. Subclasses may override this
method in order to customize the appearance of the view depending on its
selection state.
-
+
@param selected `YES` if the view should display itself as selected; `NO`
if it should display itself as unselected.
@param animated `YES` if the change in selection state is animated; `NO` if the
@@ -177,7 +177,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/*
A Boolean value indicating whether the annotation is enabled.
-
+
The default value of this property is `YES`. If the value of this property is
`NO`, the annotation view ignores touch events and cannot be selected.
Subclasses may also customize the appearance of the view depending on its
@@ -189,12 +189,12 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
A Boolean value indicating whether the annotation view is draggable.
-
+
If this property is set to `YES`, the user can drag the annotation after
pressing and holding the view, and the associated annotation object must also
implement the `-setCoordinate:` method. The default value of this property is
`NO`.
-
+
Setting this property to `YES` lets the map view know that the annotation is
always draggable. In other words, you cannot conditionalize drag operations by
attempting to stop an operation that has already been initiated; doing so can
@@ -205,7 +205,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
The current drag state of the annotation view.
-
+
All states are handled automatically when the `draggable` property is set to
`YES`. To perform a custom animation in response to a change to this property,
override the `-setDragState:animated:` method.
@@ -214,7 +214,7 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationViewDragState) {
/**
Sets the current drag state for the annotation view.
-
+
You can override this method to animate a custom annotation view as the user
drags it. As the system detects user actions that would indicate a drag, it
calls this method to update the drag state.
diff --git a/platform/ios/src/MGLAnnotationView.mm b/platform/ios/src/MGLAnnotationView.mm
index d2243bdf23..5b105cde72 100644
--- a/platform/ios/src/MGLAnnotationView.mm
+++ b/platform/ios/src/MGLAnnotationView.mm
@@ -96,7 +96,7 @@
{
center.x += _centerOffset.dx;
center.y += _centerOffset.dy;
-
+
super.center = center;
[self updateScaleTransformForViewingDistance];
}
@@ -122,14 +122,14 @@
// or 75%. The range goes from a maximum of 100% to 0% as the view moves from the top to the bottom
// along the y axis of its superview.
CGFloat maxScaleReduction = 1.0 - self.center.y / superviewHeight;
-
+
// The pitch intensity represents how much the map view is actually pitched compared to
// what is possible. The value will range from 0% (not pitched at all) to 100% (pitched as much
// as the map view will allow). The map view's maximum pitch is defined in `mbgl::util::PITCH_MAX`.
// Since it is possible for the map view to report a pitch less than 0 due to the nature of
// how the gesture information is captured, the value is guarded with MAX.
CGFloat pitchIntensity = MAX(self.mapView.camera.pitch, 0) / MGLDegreesFromRadians(mbgl::util::PITCH_MAX);
-
+
// The pitch adjusted scale is the inverse proportion of the maximum possible scale reduction
// multiplied by the pitch intensity. For example, if the maximum scale reduction is 75% and the
// map view is 50% pitched then the annotation view should be reduced by 37.5% (.75 * .5). The
@@ -154,7 +154,7 @@
[self willChangeValueForKey:@"draggable"];
_draggable = draggable;
[self didChangeValueForKey:@"draggable"];
-
+
if (draggable)
{
[self enableDrag];
@@ -174,7 +174,7 @@
[self addGestureRecognizer:recognizer];
_longPressRecognizer = recognizer;
}
-
+
if (!_panGestureRecognizer)
{
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
@@ -232,7 +232,7 @@
[self willChangeValueForKey:@"dragState"];
_dragState = dragState;
[self didChangeValueForKey:@"dragState"];
-
+
if (dragState == MGLAnnotationViewDragStateStarting)
{
[self.mapView.calloutViewForSelectedAnnotation dismissCalloutAnimated:animated];
@@ -260,7 +260,7 @@
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
BOOL isDragging = self.dragState == MGLAnnotationViewDragStateDragging;
-
+
if (gestureRecognizer == _panGestureRecognizer && !(isDragging))
{
return NO;
diff --git a/platform/ios/src/MGLCalloutView.h b/platform/ios/src/MGLCalloutView.h
index 4dc9a25be4..0481a39680 100644
--- a/platform/ios/src/MGLCalloutView.h
+++ b/platform/ios/src/MGLCalloutView.h
@@ -79,7 +79,7 @@ NS_ASSUME_NONNULL_BEGIN
Returns a Boolean value indicating whether the entire callout view “highlights”
when tapped. The default value is `YES`, which means the callout view
highlights when tapped.
-
+
The return value of this method is ignored unless the delegate also responds to
the `-calloutViewTapped` method.
*/
diff --git a/platform/ios/src/MGLCompactCalloutView.m b/platform/ios/src/MGLCompactCalloutView.m
index 3d2118ca38..e499b7832f 100644
--- a/platform/ios/src/MGLCompactCalloutView.m
+++ b/platform/ios/src/MGLCompactCalloutView.m
@@ -25,7 +25,7 @@
- (void)setRepresentedObject:(id <MGLAnnotation>)representedObject
{
_representedObject = representedObject;
-
+
if ([representedObject respondsToSelector:@selector(title)])
{
self.title = representedObject.title;
diff --git a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
index d47722819e..6db9c0db10 100644
--- a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
+++ b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
@@ -224,21 +224,21 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
[self updateFrameWithSize:MGLUserLocationAnnotationDotSize];
}
-
+
BOOL showHeadingIndicator = self.mapView.userTrackingMode == MGLUserTrackingModeFollowWithHeading;
-
+
// update heading indicator
//
if (showHeadingIndicator)
{
_headingIndicatorLayer.hidden = NO;
-
+
// heading indicator (tinted, semi-circle)
//
if ( ! _headingIndicatorLayer && self.userLocation.heading.headingAccuracy)
{
CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize;
-
+
_headingIndicatorLayer = [CALayer layer];
_headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize);
_headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0);
@@ -249,10 +249,10 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
_headingIndicatorLayer.shouldRasterize = YES;
_headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale;
_headingIndicatorLayer.drawsAsynchronously = YES;
-
+
[self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer];
}
-
+
// heading indicator accuracy mask (fan-shaped)
//
if ( ! _headingIndicatorMaskLayer && self.userLocation.heading.headingAccuracy)
@@ -260,21 +260,21 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
_headingIndicatorMaskLayer = [CAShapeLayer layer];
_headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds;
_headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
-
+
// apply the mask to the halo-radius-sized gradient layer
_headingIndicatorLayer.mask = _headingIndicatorMaskLayer;
-
+
_oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
-
+
}
else if (_oldHeadingAccuracy != self.userLocation.heading.headingAccuracy)
{
// recalculate the clipping mask based on updated accuracy
_headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
-
+
_oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
}
-
+
if (self.userLocation.heading.trueHeading >= 0)
{
_headingIndicatorLayer.affineTransform = CGAffineTransformRotate(CGAffineTransformIdentity, -MGLRadiansFromDegrees(self.mapView.direction - self.userLocation.heading.trueHeading));
@@ -294,7 +294,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
if (_accuracyRingLayer && (_oldZoom != self.mapView.zoomLevel || _oldHorizontalAccuracy != self.userLocation.location.horizontalAccuracy))
{
CGFloat accuracyRingSize = [self calculateAccuracyRingSize];
-
+
// only show the accuracy ring if it won't be obscured by the location dot
if (accuracyRingSize > MGLUserLocationAnnotationDotSize + 15)
{
@@ -341,7 +341,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
_accuracyRingLayer.opacity = 0.1;
_accuracyRingLayer.shouldRasterize = NO;
_accuracyRingLayer.allowsGroupOpacity = NO;
-
+
[self.layer addSublayer:_accuracyRingLayer];
}
@@ -396,7 +396,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
[self.layer addSublayer:_dotBorderLayer];
}
-
+
// inner dot (pulsing, tinted)
//
if ( ! _dotLayer)
diff --git a/platform/ios/src/MGLLocationManager.m b/platform/ios/src/MGLLocationManager.m
index 7a9faf5c8d..b0d2e17d5d 100644
--- a/platform/ios/src/MGLLocationManager.m
+++ b/platform/ios/src/MGLLocationManager.m
@@ -32,7 +32,7 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
if ([self isUpdatingLocation]) {
return;
}
-
+
[self configurePassiveStandardLocationManager];
[self startLocationServices];
}
@@ -46,6 +46,13 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
[self.delegate locationManagerDidStopLocationUpdates:self];
}
}
+ if(self.standardLocationManager.monitoredRegions.count > 0) {
+ for(CLRegion *region in self.standardLocationManager.monitoredRegions) {
+ if([region.identifier isEqualToString:MGLLocationManagerRegionIdentifier]) {
+ [self.standardLocationManager stopMonitoringForRegion:region];
+ }
+ }
+ }
}
#pragma mark - Utilities
@@ -78,7 +85,7 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
self.standardLocationManager.allowsBackgroundLocationUpdates = YES;
}
}
-
+
[self.standardLocationManager startUpdatingLocation];
self.updatingLocation = YES;
if ([self.delegate respondsToSelector:@selector(locationManagerDidStartLocationUpdates:)]) {
@@ -91,13 +98,13 @@ static NSString * const MGLLocationManagerRegionIdentifier = @"MGLLocationManage
if (self.backgroundLocationServiceTimeoutAllowedDate == nil) {
return;
}
-
+
if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive ||
[UIApplication sharedApplication].applicationState == UIApplicationStateInactive ) {
[self startBackgroundTimeoutTimer];
return;
}
-
+
NSTimeInterval timeIntervalSinceTimeoutAllowed = [[NSDate date] timeIntervalSinceDate:self.backgroundLocationServiceTimeoutAllowedDate];
if (timeIntervalSinceTimeoutAllowed > 0) {
[self.standardLocationManager stopUpdatingLocation];
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 62f053e96b..4a7ac308de 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -28,7 +28,7 @@ extern const CGFloat MGLMapViewDecelerationRateNormal;
/** A fast deceleration rate for a map view. */
extern const CGFloat MGLMapViewDecelerationRateFast;
-/** Disables decleration in a map view. */
+/** Disables deceleration in a map view. */
extern const CGFloat MGLMapViewDecelerationRateImmediate;
/**
@@ -47,11 +47,11 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
/**
An interactive, customizable map view with an interface similar to the one
provided by Apple’s MapKit.
-
+
Using `MGLMapView`, you can embed the map inside a view, allow users to
manipulate it with standard gestures, animate the map between different
viewpoints, and present information in the form of annotations and overlays.
-
+
The map view loads scalable vector tiles that conform to the
<a href="https://github.com/mapbox/vector-tile-spec">Mapbox Vector Tile Specification</a>.
It styles them with a style that conforms to the
@@ -59,22 +59,37 @@ typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
Such styles can be designed in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
mapbox.com.
-
+
A collection of Mapbox-hosted styles is available through the `MGLStyle`
class. These basic styles use
<a href="https://www.mapbox.com/developers/vector-tiles/mapbox-streets">Mapbox Streets</a>
or <a href="https://www.mapbox.com/satellite/">Mapbox Satellite</a> data
sources, but you can specify a custom style that makes use of your own data.
-
+
Mapbox-hosted vector tiles and styles require an API access token, which you
can obtain from the
<a href="https://www.mapbox.com/studio/account/tokens/">Mapbox account page</a>.
Access tokens associate requests to Mapbox’s vector tile and style APIs with
your Mapbox account. They also deter other developers from using your styles
without your permission.
-
+
+ Adding your own gesture recognizer to `MGLMapView` will block the corresponding
+ gesture recognizer built into `MGLMapView`. To avoid conflicts, define which
+ gesture takes precedence. For example, you can create your own
+ `UITapGestureRecognizer` that will be invoked only if the default `MGLMapView`
+ tap gesture fails:
+
+ ```swift
+ let mapTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(myCustomFunction))
+ for recognizer in mapView.gestureRecognizers! where recognizer is UITapGestureRecognizer {
+ mapTapGestureRecognizer.require(toFail: recognizer)
+ }
+ mapView.addGestureRecognizer(mapTapGestureRecognizer)
+ ```
+
@note You are responsible for getting permission to use the map data and for
ensuring that your use adheres to the relevant terms of use.
+
*/
IB_DESIGNABLE
@interface MGLMapView : UIView
@@ -84,7 +99,7 @@ IB_DESIGNABLE
/**
Initializes and returns a newly allocated map view with the specified frame
and the default style.
-
+
@param frame The frame for the view, measured in points.
@return An initialized map view.
*/
@@ -93,7 +108,7 @@ IB_DESIGNABLE
/**
Initializes and returns a newly allocated map view with the specified frame
and style URL.
-
+
@param frame The frame for the view, measured in points.
@param styleURL URL of the map style to display. The URL may be a full HTTP
or HTTPS URL, a Mapbox URL indicating the style’s map ID
@@ -107,7 +122,7 @@ IB_DESIGNABLE
/**
The receiver’s delegate.
-
+
A map view sends messages to its delegate to notify it of changes to its
contents or the viewpoint. The delegate also provides information about
annotations displayed on the map, such as the styles to apply to individual
@@ -119,29 +134,29 @@ IB_DESIGNABLE
/**
The style currently displayed in the receiver.
-
+
Unlike the `styleURL` property, this property is set to an object that allows
you to manipulate every aspect of the style locally.
-
+
If the style is loading, this property is set to `nil` until the style finishes
loading. If the style has failed to load, this property is set to `nil`.
Because the style loads asynchronously, you should manipulate it in the
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
to manipulate the style before it has finished loading.
-
+
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
- manipulate a style's sources and layers must first set the style URL to an
+ manipulate a style’s sources and layers must first set the style URL to an
explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`.
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
/**
URLs of the styles bundled with the library.
-
+
@deprecated Call the relevant class method of `MGLStyle` for the URL of a
particular default style.
*/
@@ -149,14 +164,14 @@ IB_DESIGNABLE
/**
URL of the style currently displayed in the receiver.
-
+
The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s
map ID (`mapbox://styles/{user}/{style}`), or a path to a local file
relative to the application’s resource path.
-
+
If you set this property to `nil`, the receiver will use the default style
and this property will automatically be set to that style’s URL.
-
+
If you want to modify the current style without replacing it outright, or if
you want to introspect individual style attributes, use the `style` property.
*/
@@ -164,12 +179,12 @@ IB_DESIGNABLE
/**
Reloads the style.
-
+
You do not normally need to call this method. The map view automatically
responds to changes in network connectivity by reloading the style. You may
need to call this method if you change the access token after a style has
loaded but before loading a style associated with a different Mapbox account.
-
+
This method does not bust the cache. Even if the style has recently changed on
the server, calling this method does not necessarily ensure that the map view
reflects those changes.
@@ -184,7 +199,7 @@ IB_DESIGNABLE
/**
The Mapbox logo, positioned in the lower-left corner.
-
+
@note The Mapbox terms of service, which governs the use of Mapbox-hosted
vector tiles and styles,
<a href="https://www.mapbox.com/help/mapbox-logo/">requires</a> most Mapbox
@@ -193,10 +208,10 @@ IB_DESIGNABLE
*/
@property (nonatomic, readonly) UIImageView *logoView;
-/**
+/**
A view showing legally required copyright notices and telemetry settings,
positioned at the bottom-right of the map view.
-
+
@note The Mapbox terms of service, which governs the use of Mapbox-hosted
vector tiles and styles,
<a href="https://www.mapbox.com/help/attribution/">requires</a> these
@@ -227,27 +242,27 @@ IB_DESIGNABLE
/**
A Boolean value indicating whether the map may display the user location.
-
+
Setting this property to `YES` causes the map view to use the Core Location
framework to find the current location. As long as this property is `YES`, the
map view continues to track the user’s location and update it periodically.
-
+
This property does not indicate whether the user’s position is actually visible
on the map, only whether the map view is allowed to display it. To determine
whether the user’s position is visible, use the `userLocationVisible` property.
The default value of this property is `NO`.
-
- On iOS 8 and above, your app must specify a value for
- `NSLocationWhenInUseUsageDescription` or `NSLocationAlwaysUsageDescription` in
- its `Info.plist` to satisfy the requirements of the underlying Core Location
- framework when enabling this property.
+
+ Your app must specify a value for `NSLocationWhenInUseUsageDescription` or
+ `NSLocationAlwaysUsageDescription` in its `Info.plist` to satisfy the
+ requirements of the underlying Core Location framework when enabling this
+ property.
*/
@property (nonatomic, assign) BOOL showsUserLocation;
-/**
+/**
A Boolean value indicating whether the device’s current location is visible in
the map view.
-
+
Use `showsUserLocation` to control the visibility of the on-screen user
location annotation.
*/
@@ -258,10 +273,10 @@ IB_DESIGNABLE
*/
@property (nonatomic, readonly, nullable) MGLUserLocation *userLocation;
-/**
+/**
The mode used to track the user location. The default value is
`MGLUserTrackingModeNone`.
-
+
Changing the value of this property updates the map view with an animated
transition. If you don’t want to animate the change, use the
`-setUserTrackingMode:animated:` method instead.
@@ -270,7 +285,7 @@ IB_DESIGNABLE
/**
Sets the mode used to track the user location, with an optional transition.
-
+
@param mode The mode used to track the user location.
@param animated If `YES`, there is an animated transition from the current
viewport to a viewport that results from the change to `mode`. If `NO`, the
@@ -283,7 +298,7 @@ IB_DESIGNABLE
/**
The vertical alignment of the user location annotation within the receiver. The
default value is `MGLAnnotationVerticalAlignmentCenter`.
-
+
Changing the value of this property updates the map view with an animated
transition. If you don’t want to animate the change, use the
`-setUserLocationVerticalAlignment:animated:` method instead.
@@ -293,7 +308,7 @@ IB_DESIGNABLE
/**
Sets the vertical alignment of the user location annotation within the
receiver, with an optional transition.
-
+
@param alignment The vertical alignment of the user location annotation.
@param animated If `YES`, the user location annotation animates to its new
position within the map view. If `NO`, the user location annotation
@@ -310,17 +325,17 @@ IB_DESIGNABLE
/**
The geographic coordinate that is the subject of observation as the user
location is being tracked.
-
+
By default, this property is set to an invalid coordinate, indicating that
there is no target. In course tracking mode, the target forms one of two foci
in the viewport, the other being the user location annotation. Typically, this
property is set to a destination or waypoint in a real-time navigation scene.
As the user annotation moves toward the target, the map automatically zooms in
to fit both foci optimally within the viewport.
-
+
This property has no effect if the `userTrackingMode` property is set to a
value other than `MGLUserTrackingModeFollowWithCourse`.
-
+
Changing the value of this property updates the map view with an animated
transition. If you don’t want to animate the change, use the
`-setTargetCoordinate:animated:` method instead.
@@ -330,17 +345,17 @@ IB_DESIGNABLE
/**
Sets the geographic coordinate that is the subject of observation as the user
location is being tracked, with an optional transition animation.
-
+
By default, the target coordinate is set to an invalid coordinate, indicating
that there is no target. In course tracking mode, the target forms one of two
foci in the viewport, the other being the user location annotation. Typically,
the target is set to a destination or waypoint in a real-time navigation scene.
As the user annotation moves toward the target, the map automatically zooms in
to fit both foci optimally within the viewport.
-
+
This method has no effect if the `userTrackingMode` property is set to a value
other than `MGLUserTrackingModeFollowWithCourse`.
-
+
@param targetCoordinate The target coordinate to fit within the viewport.
@param animated If `YES`, the map animates to fit the target within the map
view. If `NO`, the map fits the target instantaneously.
@@ -352,11 +367,11 @@ IB_DESIGNABLE
/**
A Boolean value that determines whether the user may zoom the map in and
out, changing the zoom level.
-
+
When this property is set to `YES`, the default, the user may zoom the map
in and out by pinching two fingers or by double tapping, holding, and moving
the finger up and down.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the map zoom
programmatically.
@@ -366,10 +381,10 @@ IB_DESIGNABLE
/**
A Boolean value that determines whether the user may scroll around the map,
changing the center coordinate.
-
+
When this property is set to `YES`, the default, the user may scroll the map
by dragging or swiping with one finger.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the map location
programmatically.
@@ -379,10 +394,10 @@ IB_DESIGNABLE
/**
A Boolean value that determines whether the user may rotate the map,
changing the direction.
-
+
When this property is set to `YES`, the default, the user may rotate the map
by moving two fingers in a circular motion.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still rotate the map
programmatically.
@@ -392,14 +407,14 @@ IB_DESIGNABLE
/**
A Boolean value that determines whether the user may change the pitch (tilt) of
the map.
-
+
When this property is set to `YES`, the default, the user may tilt the map by
vertically dragging two fingers.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the pitch of the map
programmatically.
-
+
The default value of this property is `YES`.
*/
@property(nonatomic, getter=isPitchEnabled) BOOL pitchEnabled;
@@ -419,10 +434,10 @@ IB_DESIGNABLE
/**
The geographic coordinate at the center of the map view.
-
+
Changing the value of this property centers the map on the new coordinate
without changing the current zoom level.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setCenterCoordinate:animated:` method
instead.
@@ -431,10 +446,10 @@ IB_DESIGNABLE
/**
Changes the center coordinate of the map and optionally animates the change.
-
+
Changing the center coordinate centers the map on the new coordinate without
changing the current zoom level.
-
+
@param coordinate The new center coordinate for the map.
@param animated Specify `YES` if you want the map view to scroll to the new
location or `NO` if you want the map to display the new location
@@ -445,7 +460,7 @@ IB_DESIGNABLE
/**
Changes the center coordinate and zoom level of the map and optionally animates
the change.
-
+
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@param animated Specify `YES` if you want the map view to animate scrolling and
@@ -457,7 +472,7 @@ IB_DESIGNABLE
/**
Changes the center coordinate, zoom level, and direction of the map and
optionally animates the change.
-
+
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@param direction The new direction for the map, measured in degrees relative to
@@ -471,7 +486,7 @@ IB_DESIGNABLE
/**
Changes the center coordinate, zoom level, and direction of the map, calling a
completion handler at the end of an optional animation.
-
+
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@param direction The new direction for the map, measured in degrees relative to
@@ -484,13 +499,13 @@ IB_DESIGNABLE
- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction animated:(BOOL)animated completionHandler:(nullable void (^)(void))completion;
/** The zoom level of the receiver.
-
+
In addition to affecting the visual size and detail of features on the map,
the zoom level affects the size of the vector tiles that are loaded. At zoom
level 0, each tile covers the entire world map; at zoom level 1, it covers ¼
of the world; at zoom level 2, <sup>1</sup>⁄<sub>16</sub> of the world, and
so on.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setZoomLevel:animated:` method instead.
*/
@@ -498,10 +513,10 @@ IB_DESIGNABLE
/**
Changes the zoom level of the map and optionally animates the change.
-
+
Changing the zoom level scales the map without changing the current center
coordinate.
-
+
@param zoomLevel The new zoom level for the map.
@param animated Specify `YES` if you want the map view to animate the change
to the new zoom level or `NO` if you want the map to display the new
@@ -535,11 +550,11 @@ IB_DESIGNABLE
/**
The heading of the map, measured in degrees clockwise from true north.
-
+
The value `0` means that the top edge of the map view corresponds to true
north. The value `90` means the top of the map is pointing due east. The
value `180` means the top of the map points due south, and so on.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setDirection:animated:` method instead.
*/
@@ -547,13 +562,13 @@ IB_DESIGNABLE
/**
Changes the heading of the map and optionally animates the change.
-
+
@param direction The heading of the map, measured in degrees clockwise from
true north.
@param animated Specify `YES` if you want the map view to animate the change
to the new heading or `NO` if you want the map to display the new
heading immediately.
-
+
Changing the heading rotates the map without changing the current center
coordinate or zoom level.
*/
@@ -566,7 +581,7 @@ IB_DESIGNABLE
/**
Resets the map to the current style’s default viewport.
-
+
If the style doesn’t specify a default viewport, the map resets to a minimum
zoom level, a center coordinate of (0, 0), and a northern heading.
*/
@@ -574,7 +589,7 @@ IB_DESIGNABLE
/**
The coordinate bounds visible in the receiver’s viewport.
-
+
Changing the value of this property updates the receiver immediately. If you
want to animate the change, call `-setVisibleCoordinateBounds:animated:`
instead.
@@ -584,7 +599,7 @@ IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit the given coordinate bounds,
optionally animating the change.
-
+
@param bounds The bounds that the viewport will show in its entirety.
@param animated Specify `YES` to animate the change by smoothly scrolling
and zooming or `NO` to immediately display the given bounds.
@@ -594,7 +609,7 @@ IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit the given coordinate bounds and
optionally some additional padding on each side.
-
+
@param bounds The bounds that the viewport will show in its entirety.
@param insets The minimum padding (in screen points) that will be visible
around the given coordinate bounds.
@@ -606,7 +621,7 @@ IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit all of the given coordinates and
optionally some additional padding on each side.
-
+
@param coordinates The coordinates that the viewport will show.
@param count The number of coordinates. This number must not be greater than
the number of elements in `coordinates`.
@@ -620,7 +635,7 @@ IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit all of the given coordinates and
optionally some additional padding on each side.
-
+
@param coordinates The coordinates that the viewport will show.
@param count The number of coordinates. This number must not be greater than
the number of elements in `coordinates`.
@@ -671,7 +686,7 @@ IB_DESIGNABLE
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition animation.
-
+
@param camera The new viewpoint.
@param animated Specify `YES` if you want the map view to animate the change to
the new viewpoint or `NO` if you want the map to display the new viewpoint
@@ -682,7 +697,7 @@ IB_DESIGNABLE
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition duration and timing function.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -696,7 +711,7 @@ IB_DESIGNABLE
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition duration and timing function.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -712,10 +727,10 @@ IB_DESIGNABLE
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and a default duration based on the length of the flight
path.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param completion The block to execute after the animation finishes.
*/
@@ -724,10 +739,10 @@ IB_DESIGNABLE
/**
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and an optional transition duration.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -740,10 +755,10 @@ IB_DESIGNABLE
/**
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and an optional transition duration and peak altitude.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -759,7 +774,7 @@ IB_DESIGNABLE
/**
Returns the camera that best fits the given coordinate bounds.
-
+
@param bounds The coordinate bounds to fit to the receiver’s viewport.
@return A camera object centered on the same location as the coordinate
bounds with zoom level as high (close to the ground) as possible while still
@@ -771,7 +786,7 @@ IB_DESIGNABLE
/**
Returns the camera that best fits the given coordinate bounds, optionally with
some additional padding on each side.
-
+
@param bounds The coordinate bounds to fit to the receiver’s viewport.
@param insets The minimum padding (in screen points) that would be visible
around the returned camera object if it were set as the receiver’s camera.
@@ -785,17 +800,17 @@ IB_DESIGNABLE
/**
Returns the point in this view’s coordinate system on which to "anchor" in
response to a user-initiated gesture.
-
+
For example, a pinch-to-zoom gesture would anchor the map at the midpoint of
the pinch.
-
+
If the `userTrackingMode` property is not `MGLUserTrackingModeNone`, the
user annotation is used as the anchor point.
-
+
Subclasses may override this method to provide specialized behavior - for
example, anchoring on the map’s center point to provide a "locked" zooming
mode.
-
+
@param gesture An anchorable user gesture.
@return The point on which to anchor in response to the gesture.
*/
@@ -804,17 +819,17 @@ IB_DESIGNABLE
/**
The distance from the edges of the map view’s frame to the edges of the map
view’s logical viewport.
-
+
When the value of this property is equal to `UIEdgeInsetsZero`, viewport
properties such as `centerCoordinate` assume a viewport that matches the map
view’s frame. Otherwise, those properties are inset, excluding part of the
frame from the viewport. For instance, if the only the top edge is inset, the
map center is effectively shifted downward.
-
+
When the map view’s superview is an instance of `UIViewController` whose
`automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this
property may be overridden at any time.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setContentInset:animated:` method
instead.
@@ -824,17 +839,17 @@ IB_DESIGNABLE
/**
Sets the distance from the edges of the map view’s frame to the edges of the
map view’s logical viewport with an optional transition animation.
-
+
When the value of this property is equal to `UIEdgeInsetsZero`, viewport
properties such as `centerCoordinate` assume a viewport that matches the map
view’s frame. Otherwise, those properties are inset, excluding part of the
frame from the viewport. For instance, if the only the top edge is inset, the
map center is effectively shifted downward.
-
+
When the map view’s superview is an instance of `UIViewController` whose
`automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this
property may be overridden at any time.
-
+
@param contentInset The new values to inset the content by.
@param animated Specify `YES` if you want the map view to animate the change to
the content inset or `NO` if you want the map to inset the content
@@ -847,7 +862,7 @@ IB_DESIGNABLE
/**
Converts a point in the given view’s coordinate system to a geographic
coordinate.
-
+
@param point The point to convert.
@param view The view in whose coordinate system the point is expressed.
@return The geographic coordinate at the given point.
@@ -857,7 +872,7 @@ IB_DESIGNABLE
/**
Converts a geographic coordinate to a point in the given view’s coordinate
system.
-
+
@param coordinate The geographic coordinate to convert.
@param view The view in whose coordinate system the returned point should be
expressed. If this parameter is `nil`, the returned point is expressed
@@ -871,7 +886,7 @@ IB_DESIGNABLE
/**
Converts a rectangle in the given view’s coordinate system to a geographic
bounding box.
-
+
@param rect The rectangle to convert.
@param view The view in whose coordinate system the rectangle is expressed.
@return The geographic bounding box coextensive with the given rectangle.
@@ -881,7 +896,7 @@ IB_DESIGNABLE
/**
Converts a geographic bounding box to a rectangle in the given view’s
coordinate system.
-
+
@param bounds The geographic bounding box to convert.
@param view The view in whose coordinate system the returned rectangle should
be expressed. If this parameter is `nil`, the returned rectangle is
@@ -893,11 +908,11 @@ IB_DESIGNABLE
/**
Returns the distance spanned by one point in the map view’s coordinate system
at the given latitude and current zoom level.
-
+
The distance between points decreases as the latitude approaches the poles.
This relationship parallels the relationship between longitudinal coordinates
at different latitudes.
-
+
@param latitude The latitude of the geographic coordinate represented by the
point.
@return The distance in meters spanned by a single point.
@@ -910,7 +925,7 @@ IB_DESIGNABLE
/**
The complete list of annotations associated with the receiver. (read-only)
-
+
The objects in this array must adopt the `MGLAnnotation` protocol. If no
annotations are associated with the map view, the value of this property is
`nil`.
@@ -918,9 +933,9 @@ IB_DESIGNABLE
@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
/**
- The complete list of annotations associated with the receiver that are
+ The complete list of annotations associated with the receiver that are
currently visible.
-
+
The objects in this array must adopt the `MGLAnnotation` protocol. If no
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`.
@@ -929,12 +944,12 @@ IB_DESIGNABLE
/**
Adds an annotation to the map view.
-
- @note `MGLMultiPolyline`, `MGLMultiPolygon`, `MGLShapeCollection`, and
- `MGLPointCollection` objects cannot be added to the map view at this time.
- Any multipoint, multipolyline, multipolygon, shape or point collection
+
+ @note `MGLMultiPolyline`, `MGLMultiPolygon`, `MGLShapeCollection`, and
+ `MGLPointCollection` objects cannot be added to the map view at this time.
+ Any multipoint, multipolyline, multipolygon, shape or point collection
object that is specified is silently ignored.
-
+
@param annotation The annotation object to add to the receiver. This object
must conform to the `MGLAnnotation` protocol. The map view retains the
annotation object. */
@@ -942,13 +957,13 @@ IB_DESIGNABLE
/**
Adds an array of annotations to the map view.
-
+
@note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
cannot be added to the map view at this time. Nor can `MGLMultiPoint`
objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any
multipoint, multipolyline, multipolygon, or shape collection objects that
are specified are silently ignored.
-
+
@param annotations An array of annotation objects. Each object in the array
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
@@ -957,11 +972,11 @@ IB_DESIGNABLE
/**
Removes an annotation from the map view, deselecting it if it is selected.
-
+
Removing an annotation object dissociates it from the map view entirely,
preventing it from being displayed on the map. Thus you would typically call
this method only when you want to hide or delete a given annotation.
-
+
@param annotation The annotation object to remove. This object must conform
to the `MGLAnnotation` protocol
*/
@@ -970,11 +985,11 @@ IB_DESIGNABLE
/**
Removes an array of annotations from the map view, deselecting any selected
annotations in the array.
-
+
Removing annotation objects dissociates them from the map view entirely,
preventing them from being displayed on the map. Thus you would typically
call this method only when you want to hide or delete the given annotations.
-
+
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
@@ -983,20 +998,20 @@ IB_DESIGNABLE
/**
Returns an `MGLAnnotationView` if the given annotation is currently associated
with a view, otherwise nil.
-
- @param annotation The annotation associated with the view.
+
+ @param annotation The annotation associated with the view.
Annotation must conform to the `MGLAnnotation` protocol.
*/
- (nullable MGLAnnotationView *)viewForAnnotation:(id <MGLAnnotation>)annotation;
/**
Returns a reusable annotation image object associated with its identifier.
-
+
For performance reasons, you should generally reuse `MGLAnnotationImage`
objects for identical-looking annotations in your map views. Dequeueing
saves time and memory during performance-critical operations such as
scrolling.
-
+
@param identifier A string identifying the annotation image to be reused.
This string is the same one you specify when initially returning the
annotation image object using the `-mapView:imageForAnnotation:` method.
@@ -1007,12 +1022,12 @@ IB_DESIGNABLE
/**
Returns a reusable annotation view object associated with its identifier.
-
+
For performance reasons, you should generally reuse `MGLAnnotationView`
objects for identical-looking annotations in your map views. Dequeueing
saves time and memory during performance-critical operations such as
scrolling.
-
+
@param identifier A string identifying the annotation view to be reused.
This string is the same one you specify when initially returning the
annotation view object using the `-mapView:viewForAnnotation:` method.
@@ -1022,12 +1037,12 @@ IB_DESIGNABLE
- (nullable __kindof MGLAnnotationView *)dequeueReusableAnnotationViewWithIdentifier:(NSString *)identifier;
/**
- Returns the list of annotations associated with the receiver that intersect with
+ Returns the list of annotations associated with the receiver that intersect with
the given rectangle.
-
+
@param rect A rectangle expressed in the map view’s coordinate system.
@return An array of objects that adopt the `MGLAnnotation` protocol or `nil` if
- no annotations associated with the map view are currently visible in the
+ no annotations associated with the map view are currently visible in the
rectangle.
*/
- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect;
@@ -1036,7 +1051,7 @@ IB_DESIGNABLE
/**
The currently selected annotations.
-
+
Assigning a new array to this property selects only the first annotation in
the array.
*/
@@ -1044,10 +1059,10 @@ IB_DESIGNABLE
/**
Selects an annotation and displays a callout view for it.
-
+
If the given annotation is not visible within the current viewport, this
method has no effect.
-
+
@param annotation The annotation object to select.
@param animated If `YES`, the callout view is animated into position.
*/
@@ -1055,7 +1070,7 @@ IB_DESIGNABLE
/**
Deselects an annotation and hides its callout view.
-
+
@param annotation The annotation object to deselect.
@param animated If `YES`, the callout view is animated offscreen.
*/
@@ -1065,18 +1080,18 @@ IB_DESIGNABLE
/**
Adds a single overlay object to the map.
-
+
To remove an overlay from a map, use the `-removeOverlay:` method.
-
+
@param overlay The overlay object to add. This object must conform to the
`MGLOverlay` protocol. */
- (void)addOverlay:(id <MGLOverlay>)overlay;
/**
Adds an array of overlay objects to the map.
-
+
To remove multiple overlays from a map, use the `-removeOverlays:` method.
-
+
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
@@ -1084,19 +1099,19 @@ IB_DESIGNABLE
/**
Removes a single overlay object from the map.
-
+
If the specified overlay is not currently associated with the map view, this
method does nothing.
-
+
@param overlay The overlay object to remove.
*/
- (void)removeOverlay:(id <MGLOverlay>)overlay;
/**
Removes one or more overlay objects from the map.
-
+
If a given overlay object is not associated with the map view, it is ignored.
-
+
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
@@ -1106,12 +1121,12 @@ IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with a given point.
-
+
This method may return features from any of the map’s style layers. To restrict
the search to a particular layer or layers, use the
`-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
information about searching for map features, see that method’s documentation.
-
+
@param point A point expressed in the map view’s coordinate system.
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
@@ -1121,13 +1136,13 @@ IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with a given point,
restricted to the given style layers.
-
+
Each object in the returned array represents a feature rendered by the
current style and provides access to attributes specified by the relevant
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
The returned array includes features specified in vector and GeoJSON tile
sources but does not include anything from raster, image, or video sources.
-
+
Only visible features are returned. For example, suppose the current style uses
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
@@ -1140,30 +1155,30 @@ IB_DESIGNABLE
other attributes). The dictionary contains only the attributes provided by the
tile source; it does not include computed attribute values or rules about how
the feature is rendered by the current style.
-
+
The returned array is sorted by z-order, starting with the topmost rendered
feature and ending with the bottommost rendered feature. A feature that is
rendered multiple times due to wrapping across the antimeridian at low zoom
levels is included only once, subject to the caveat that follows.
-
+
Features come from tiled vector data or GeoJSON data that is converted to tiles
internally, so feature geometries are clipped at tile boundaries and features
may appear duplicated across tiles. For example, suppose the specified point
lies along a road that spans the screen. The resulting array includes those
parts of the road that lie within the map tile that contain the specified
point, even if the road extends into other tiles.
-
+
To find out the layer names in a particular style, view the style in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
-
+
@param point A point expressed in the map view’s coordinate system.
@param styleLayerIdentifiers A set of strings that correspond to the names of
layers defined in the current style. Only the features contained in these
@@ -1176,12 +1191,12 @@ IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with the given
rectangle.
-
+
This method may return features from any of the map’s style layers. To restrict
the search to a particular layer or layers, use the
`-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
information about searching for map features, see that method’s documentation.
-
+
@param rect A rectangle expressed in the map view’s coordinate system.
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
@@ -1191,13 +1206,13 @@ IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with the given
rectangle, restricted to the given style layers.
-
+
Each object in the returned array represents a feature rendered by the
current style and provides access to attributes specified by the relevant
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
The returned array includes features specified in vector and GeoJSON tile
sources but does not include anything from raster, image, or video sources.
-
+
Only visible features are returned. For example, suppose the current style uses
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
@@ -1210,12 +1225,12 @@ IB_DESIGNABLE
dictionary contains only the attributes provided by the tile source; it does
not include computed attribute values or rules about how the feature is
rendered by the current style.
-
+
The returned array is sorted by z-order, starting with the topmost rendered
feature and ending with the bottommost rendered feature. A feature that is
rendered multiple times due to wrapping across the antimeridian at low zoom
levels is included only once, subject to the caveat that follows.
-
+
Features come from tiled vector data or GeoJSON data that is converted to tiles
internally, so feature geometries are clipped at tile boundaries and features
may appear duplicated across tiles. For example, suppose the specified
@@ -1223,18 +1238,18 @@ IB_DESIGNABLE
includes those parts of the road that lie within the map tiles covering the
specified rectangle, even if the road extends into other tiles. The portion of
the road within each map tile is included individually.
-
+
To find out the layer names in a particular style, view the style in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
-
+
@param rect A rectangle expressed in the map view’s coordinate system.
@param styleLayerIdentifiers A set of strings that correspond to the names of
layers defined in the current style. Only the features contained in these
@@ -1248,7 +1263,7 @@ IB_DESIGNABLE
/**
The options that determine which debugging aids are shown on the map.
-
+
These options are all disabled by default and should remain disabled in
released software for performance and aesthetic reasons.
*/
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index e6ebd4492f..7119544158 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -29,12 +29,14 @@
#include <mbgl/util/default_styles.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
#import "Mapbox.h"
#import "MGLFeature_Private.h"
#import "MGLGeometry_Private.h"
#import "MGLMultiPoint_Private.h"
#import "MGLOfflineStorage_Private.h"
+#import "MGLFoundation_Private.h"
#import "NSBundle+MGLAdditions.h"
#import "NSDate+MGLAdditions.h"
@@ -99,7 +101,7 @@ const double MGLMinimumZoomLevelForUserTracking = 10.5;
/// Initial zoom level when entering user tracking mode from a low zoom level.
const double MGLDefaultZoomLevelForUserTracking = 14.0;
-const NSUInteger MGLTargetFrameInterval = 1; //Target FPS will be 60 divided by this value
+const NSUInteger MGLTargetFrameInterval = 1; // Target FPS will be 60 divided by this value
/// Tolerance for snapping to true north, measured in degrees in either direction.
const CLLocationDirection MGLToleranceForSnappingToNorth = 7;
@@ -136,11 +138,6 @@ typedef std::unordered_map<MGLAnnotationTag, MGLAnnotationContext> MGLAnnotation
/// Mapping from an annotation object to an annotation tag.
typedef std::map<id<MGLAnnotation>, MGLAnnotationTag> MGLAnnotationObjectTagMap;
-/// Initializes the run loop shim that lives on the main thread.
-void MGLinitializeRunLoop() {
- static mbgl::util::RunLoop mainRunLoop;
-}
-
mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function)
{
if ( ! function)
@@ -269,7 +266,7 @@ public:
{
mbgl::Map *_mbglMap;
MBGLView *_mbglView;
- mbgl::ThreadPool *_mbglThreadPool;
+ std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
BOOL _opaque;
@@ -277,7 +274,7 @@ public:
MGLAnnotationTagContextMap _annotationContextsByAnnotationTag;
MGLAnnotationObjectTagMap _annotationTagsByAnnotation;
-
+
/// Tag of the selected annotation. If the user location annotation is selected, this ivar is set to `MGLAnnotationTagNotFound`.
MGLAnnotationTag _selectedAnnotationTag;
@@ -312,8 +309,10 @@ public:
BOOL _delegateHasLineWidthsForShapeAnnotations;
MGLCompassDirectionFormatter *_accessibilityCompassFormatter;
-
+
NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfos;
+
+ MGLReachability *_reachability;
}
#pragma mark - Setup & Teardown -
@@ -368,7 +367,7 @@ public:
- (void)setStyleURL:(nullable NSURL *)styleURL
{
if (_isTargetingInterfaceBuilder) return;
-
+
if ( ! styleURL)
{
styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
@@ -392,10 +391,8 @@ public:
- (void)commonInit
{
- MGLinitializeRunLoop();
-
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
- _opaque = YES;
+ _opaque = NO;
BOOL background = [UIApplication sharedApplication].applicationState == UIApplicationStateBackground;
if (!background)
@@ -425,7 +422,7 @@ public:
// setup mbgl map
mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
- _mbglThreadPool = new mbgl::ThreadPool(4);
+ _mbglThreadPool = mbgl::sharedThreadPool();
_mbglMap = new mbgl::Map(*_mbglView, self.size, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default);
[self validateTileCacheSize];
@@ -440,12 +437,12 @@ public:
name:kMGLReachabilityChangedNotification
object:nil];
- MGLReachability* reachability = [MGLReachability reachabilityForInternetConnection];
- if ([reachability isReachable])
+ _reachability = [MGLReachability reachabilityForInternetConnection];
+ if ([_reachability isReachable])
{
_isWaitingForRedundantReachableNotification = YES;
}
- [reachability startNotifier];
+ [_reachability startNotifier];
// Set up annotation management and selection state.
_annotationImagesByIdentifier = [NSMutableDictionary dictionary];
@@ -652,6 +649,8 @@ public:
- (void)reachabilityChanged:(NSNotification *)notification
{
+ MGLAssertIsMainThread();
+
MGLReachability *reachability = [notification object];
if ( ! _isWaitingForRedundantReachableNotification && [reachability isReachable])
{
@@ -662,6 +661,8 @@ public:
- (void)dealloc
{
+ [_reachability stopNotifier];
+
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_attributionButton removeObserver:self forKeyPath:@"hidden"];
@@ -687,12 +688,6 @@ public:
_mbglView = nullptr;
}
- if (_mbglThreadPool)
- {
- delete _mbglThreadPool;
- _mbglThreadPool = nullptr;
- }
-
if ([[EAGLContext currentContext] isEqual:_context])
{
[EAGLContext setCurrentContext:nil];
@@ -718,6 +713,8 @@ public:
- (void)didReceiveMemoryWarning
{
+ MGLAssertIsMainThread();
+
_mbglMap->onLowMemory();
}
@@ -1197,6 +1194,8 @@ public:
_mbglMap->cancelTransitions();
+ MGLMapCamera *oldCamera = self.camera;
+
if (pan.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGesturePanStart forRecognizer:pan];
@@ -1208,8 +1207,15 @@ public:
else if (pan.state == UIGestureRecognizerStateChanged)
{
CGPoint delta = [pan translationInView:pan.view];
- _mbglMap->moveBy({ delta.x, delta.y });
- [pan setTranslation:CGPointZero inView:pan.view];
+
+ MGLMapCamera *toCamera = [self cameraByPanningWithTranslation:delta panGesture:pan];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->moveBy({ delta.x, delta.y });
+ [pan setTranslation:CGPointZero inView:pan.view];
+ }
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
}
@@ -1226,7 +1232,13 @@ public:
if (drift)
{
CGPoint offset = CGPointMake(velocity.x * self.decelerationRate / 4, velocity.y * self.decelerationRate / 4);
- _mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSecondsFromTimeInterval(self.decelerationRate));
+ MGLMapCamera *toCamera = [self cameraByPanningWithTranslation:offset panGesture:pan];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSecondsFromTimeInterval(self.decelerationRate));
+ }
}
[self notifyGestureDidEndWithDrift:drift];
@@ -1242,6 +1254,7 @@ public:
MGLEventKeyZoomLevel: @(zoom)
}];
}
+
}
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch
@@ -1253,6 +1266,7 @@ public:
_mbglMap->cancelTransitions();
CGPoint centerPoint = [self anchorPointForGesture:pinch];
+ MGLMapCamera *oldCamera = self.camera;
if (pinch.state == UIGestureRecognizerStateBegan)
{
@@ -1265,11 +1279,17 @@ public:
else if (pinch.state == UIGestureRecognizerStateChanged)
{
CGFloat newScale = self.scale * pinch.scale;
-
- if (log2(newScale) < _mbglMap->getMinZoom()) return;
-
- _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
-
+ double zoom = log2(newScale);
+ if (zoom < _mbglMap->getMinZoom()) return;
+
+ // Calculates the final camera zoom, has no effect within current map camera.
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:centerPoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ }
// The gesture recognizer only reports the gesture’s current center
// point, so use the previous center point to anchor the transition.
// If the number of touches has changed, the remembered center point is
@@ -1280,7 +1300,6 @@ public:
_mbglMap->setLatLng(MGLLatLngFromLocationCoordinate2D(centerCoordinate),
mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
}
-
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
}
else if (pinch.state == UIGestureRecognizerStateEnded || pinch.state == UIGestureRecognizerStateCancelled)
@@ -1313,14 +1332,25 @@ public:
{
velocity = 0;
}
-
- if (velocity && duration)
+
+ BOOL drift = velocity && duration;
+
+ // Calculates the final camera zoom, this has no effect within current map camera.
+ double zoom = log2(newScale);
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:centerPoint];
+
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSecondsFromTimeInterval(duration));
+ drift = NO;
+ } else {
+ if (drift)
+ {
+ _mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSecondsFromTimeInterval(duration));
+ }
}
- [self notifyGestureDidEndWithDrift:velocity && duration];
-
+ [self notifyGestureDidEndWithDrift:drift];
[self unrotateIfNeededForGesture];
}
@@ -1335,7 +1365,8 @@ public:
_mbglMap->cancelTransitions();
CGPoint centerPoint = [self anchorPointForGesture:rotate];
-
+ MGLMapCamera *oldCamera = self.camera;
+
if (rotate.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGestureRotateStart forRecognizer:rotate];
@@ -1360,10 +1391,17 @@ public:
newDegrees = fminf(newDegrees, 30);
newDegrees = fmaxf(newDegrees, -30);
}
-
- _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
-
+
+ MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ }
+
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
+
}
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
{
@@ -1375,16 +1413,22 @@ public:
CGFloat newRadians = radians + velocity * decelerationRate * 0.1;
CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
- _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSecondsFromTimeInterval(decelerationRate));
-
- [self notifyGestureDidEndWithDrift:YES];
-
- __weak MGLMapView *weakSelf = self;
-
- [self animateWithDelay:decelerationRate animations:^
- {
- [weakSelf unrotateIfNeededForGesture];
- }];
+ MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSecondsFromTimeInterval(decelerationRate));
+
+ [self notifyGestureDidEndWithDrift:YES];
+
+ __weak MGLMapView *weakSelf = self;
+
+ [self animateWithDelay:decelerationRate animations:^
+ {
+ [weakSelf unrotateIfNeededForGesture];
+ }];
+ }
}
else
{
@@ -1431,9 +1475,9 @@ public:
/**
Returns the annotation that would be selected by a tap gesture recognizer.
-
+
This is used when a gesture is recognized, and to check if the gesture should be recognized.
-
+
@param singleTap An in progress tap gesture recognizer.
@param persist True to remember the cycleable set of annotations. @see annotationTagAtPoint:persistingResults
*/
@@ -1453,9 +1497,9 @@ public:
// Get the tap point within the custom hit test layer.
tapPointForUserLocation = [singleTap locationInView:self.userLocationAnnotationView];
}
-
+
CALayer *hitLayer = [self.userLocationAnnotationView.hitTestLayer hitTest:tapPointForUserLocation];
-
+
if (hitLayer)
{
if ( ! _userLocationAnnotationIsSelected)
@@ -1465,7 +1509,7 @@ public:
return nil;
}
}
-
+
// Handle the case of an offset annotation view by converting the tap point to be the geo location
// of the annotation itself that the view represents
for (MGLAnnotationView *view in self.annotationContainerView.annotationViews)
@@ -1477,7 +1521,7 @@ public:
}
}
}
-
+
MGLAnnotationTag hitAnnotationTag = [self annotationTagAtPoint:tapPoint persistingResults:persist];
if (hitAnnotationTag != MGLAnnotationTagNotFound)
{
@@ -1488,7 +1532,7 @@ public:
return annotation;
}
}
-
+
return nil;
}
@@ -1500,18 +1544,29 @@ public:
if (doubleTap.state == UIGestureRecognizerStateEnded)
{
- [self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap];
- CGPoint gesturePoint = [self anchorPointForGesture:doubleTap];
+ MGLMapCamera *oldCamera = self.camera;
- mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- _mbglMap->scaleBy(2, center, MGLDurationInSecondsFromTimeInterval(MGLAnimationDuration));
+ double newZoom = round(self.zoomLevel) + 1.0;
- __weak MGLMapView *weakSelf = self;
+ CGPoint gesturePoint = [self anchorPointForGesture:doubleTap];
- [self animateWithDelay:MGLAnimationDuration animations:^
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:gesturePoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- [weakSelf unrotateIfNeededForGesture];
- }];
+ [self trackGestureEvent:MGLEventGestureDoubleTap forRecognizer:doubleTap];
+
+ mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
+ _mbglMap->setZoom(newZoom, center, MGLDurationInSecondsFromTimeInterval(MGLAnimationDuration));
+
+ __weak MGLMapView *weakSelf = self;
+
+ [self animateWithDelay:MGLAnimationDuration animations:^
+ {
+ [weakSelf unrotateIfNeededForGesture];
+ }];
+ }
}
}
@@ -1529,17 +1584,27 @@ public:
}
else if (twoFingerTap.state == UIGestureRecognizerStateEnded)
{
- CGPoint gesturePoint = [self anchorPointForGesture:twoFingerTap];
+ MGLMapCamera *oldCamera = self.camera;
- mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- _mbglMap->scaleBy(0.5, center, MGLDurationInSecondsFromTimeInterval(MGLAnimationDuration));
+ double newZoom = round(self.zoomLevel) - 1.0;
- __weak MGLMapView *weakSelf = self;
+ CGPoint gesturePoint = [self anchorPointForGesture:twoFingerTap];
- [self animateWithDelay:MGLAnimationDuration animations:^
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:newZoom aroundAnchorPoint:gesturePoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- [weakSelf unrotateIfNeededForGesture];
- }];
+ mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
+ _mbglMap->setZoom(newZoom, center, MGLDurationInSecondsFromTimeInterval(MGLAnimationDuration));
+
+ __weak MGLMapView *weakSelf = self;
+
+ [self animateWithDelay:MGLAnimationDuration animations:^
+ {
+ [weakSelf unrotateIfNeededForGesture];
+ }];
+ }
}
}
@@ -1548,7 +1613,7 @@ public:
if ( ! self.isZoomEnabled) return;
_mbglMap->cancelTransitions();
-
+
if (quickZoom.state == UIGestureRecognizerStateBegan)
{
[self trackGestureEvent:MGLEventGestureQuickZoom forRecognizer:quickZoom];
@@ -1568,9 +1633,21 @@ public:
if (newZoom < _mbglMap->getMinZoom()) return;
CGPoint centerPoint = [self anchorPointForGesture:quickZoom];
-
- _mbglMap->scaleBy(powf(2, newZoom) / _mbglMap->getScale(),
- mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+
+ MGLMapCamera *oldCamera = self.camera;
+
+ double zoom = self.zoomLevel;
+ double scale = powf(2, newZoom) / _mbglMap->getScale();
+
+ double estimatedZoom = zoom * scale;
+
+ MGLMapCamera *toCamera = [self cameraByZoomingToZoomLevel:estimatedZoom aroundAnchorPoint:centerPoint];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->scaleBy(scale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ }
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
}
@@ -1586,6 +1663,7 @@ public:
if ( ! self.isPitchEnabled) return;
_mbglMap->cancelTransitions();
+ MGLMapCamera *oldCamera = self.camera;
if (twoFingerDrag.state == UIGestureRecognizerStateBegan)
{
@@ -1602,7 +1680,13 @@ public:
CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];
- _mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
+
+ if (![self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)] ||
+ [self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ _mbglMap->setPitch(pitchNew, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y });
+ }
[self notifyMapChange:mbgl::MapChangeRegionIsChanging];
}
@@ -1611,6 +1695,62 @@ public:
[self notifyGestureDidEndWithDrift:NO];
[self unrotateIfNeededForGesture];
}
+
+}
+
+- (MGLMapCamera *)cameraByPanningWithTranslation:(CGPoint)endPoint panGesture:(UIPanGestureRecognizer *)pan
+{
+ MGLMapCamera *panCamera = [self.camera copy];
+
+ CGPoint centerPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
+ CGPoint endCameraPoint = CGPointMake(centerPoint.x - endPoint.x, centerPoint.y - endPoint.y);
+ CLLocationCoordinate2D panCoordinate = [self convertPoint:endCameraPoint toCoordinateFromView:pan.view];
+
+ panCamera.centerCoordinate = panCoordinate;
+
+ return panCamera;
+}
+
+- (MGLMapCamera *)cameraByZoomingToZoomLevel:(double)zoom aroundAnchorPoint:(CGPoint)anchorPoint
+{
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
+ mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+ MGLMapCamera *camera;
+
+ mbgl::ScreenCoordinate anchor = mbgl::ScreenCoordinate { anchorPoint.x, anchorPoint.y };
+ currentCameraOptions.zoom = mbgl::util::clamp(zoom, self.minimumZoomLevel, self.maximumZoomLevel);
+ currentCameraOptions.anchor = anchor;
+ camera = [self cameraForCameraOptions:currentCameraOptions];
+
+ return camera;
+}
+
+- (MGLMapCamera *)cameraByRotatingToDirection:(CLLocationDirection)degrees aroundAnchorPoint:(CGPoint)anchorPoint
+{
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
+ mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+
+ MGLMapCamera *camera;
+
+ mbgl::ScreenCoordinate anchor = mbgl::ScreenCoordinate { anchorPoint.x, anchorPoint.y };
+ currentCameraOptions.angle = degrees * mbgl::util::DEG2RAD;
+ currentCameraOptions.anchor = anchor;
+ camera = [self cameraForCameraOptions:currentCameraOptions];
+
+ return camera;
+}
+
+- (MGLMapCamera *)cameraByTiltingToPitch:(CGFloat)pitch
+{
+ mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
+ mbgl::CameraOptions currentCameraOptions = _mbglMap->getCameraOptions(padding);
+
+ MGLMapCamera *camera;
+
+ currentCameraOptions.pitch = pitch * mbgl::util::DEG2RAD;
+ camera = [self cameraForCameraOptions:currentCameraOptions];
+
+ return camera;
}
- (CGPoint)anchorPointForGesture:(UIGestureRecognizer *)gesture {
@@ -1649,7 +1789,7 @@ public:
}
else if (gestureRecognizer == _singleTapGestureRecognizer)
{
- //Gesture will be recognized if it could deselect an annotation
+ // Gesture will be recognized if it could deselect an annotation
if(!self.selectedAnnotation)
{
id<MGLAnnotation>annotation = [self annotationForGestureRecognizer:(UITapGestureRecognizer*)gestureRecognizer persistingResults:NO];
@@ -1734,16 +1874,16 @@ public:
cancelButtonTitle:NSLocalizedStringWithDefaultValue(@"CANCEL", nil, nil, @"Cancel", @"")
destructiveButtonTitle:nil
otherButtonTitles:nil];
-
+
_attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] linkColor:nil];
for (MGLAttributionInfo *info in _attributionInfos)
{
NSString *title = [info.title.string mgl_titleCasedStringWithLocale:[NSLocale currentLocale]];
[self.attributionSheet addButtonWithTitle:title];
}
-
+
[self.attributionSheet addButtonWithTitle:NSLocalizedStringWithDefaultValue(@"TELEMETRY_NAME", nil, nil, @"Mapbox Telemetry", @"Action in attribution sheet")];
-
+
[self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES];
}
@@ -2274,8 +2414,6 @@ public:
- (void)_setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate edgePadding:(UIEdgeInsets)insets zoomLevel:(double)zoomLevel direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
- _mbglMap->cancelTransitions();
-
mbgl::CameraOptions cameraOptions;
cameraOptions.center = MGLLatLngFromLocationCoordinate2D(centerCoordinate);
cameraOptions.padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
@@ -2302,6 +2440,20 @@ public:
});
};
}
+
+ MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
+ if ([self.camera isEqualToMapCamera:camera])
+ {
+ if (completion)
+ {
+ [self animateWithDelay:duration animations:^{
+ completion();
+ }];
+ }
+ return;
+ }
+
+ _mbglMap->cancelTransitions();
_mbglMap->easeTo(cameraOptions, animationOptions);
}
@@ -2420,9 +2572,6 @@ public:
- (void)_setVisibleCoordinates:(const CLLocationCoordinate2D *)coordinates count:(NSUInteger)count edgePadding:(UIEdgeInsets)insets direction:(CLLocationDirection)direction duration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
- _mbglMap->cancelTransitions();
-
- [self willChangeValueForKey:@"visibleCoordinateBounds"];
mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(insets);
padding += MGLEdgeInsetsFromNSEdgeInsets(self.contentInset);
std::vector<mbgl::LatLng> latLngs;
@@ -2452,6 +2601,21 @@ public:
});
};
}
+
+ MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
+ if ([self.camera isEqualToMapCamera:camera])
+ {
+ if (completion)
+ {
+ [self animateWithDelay:duration animations:^{
+ completion();
+ }];
+ }
+ return;
+ }
+
+ [self willChangeValueForKey:@"visibleCoordinateBounds"];
+ _mbglMap->cancelTransitions();
_mbglMap->easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"visibleCoordinateBounds"];
}
@@ -2537,14 +2701,6 @@ public:
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion
{
- self.userTrackingMode = MGLUserTrackingModeNone;
- _mbglMap->cancelTransitions();
- if ([self.camera isEqual:camera])
- {
- return;
- }
-
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:self.contentInset];
mbgl::AnimationOptions animationOptions;
if (duration > 0)
{
@@ -2559,8 +2715,21 @@ public:
});
};
}
+
+ if ([self.camera isEqualToMapCamera:camera])
+ {
+ if (completion)
+ {
+ [self animateWithDelay:duration animations:^{
+ completion();
+ }];
+ }
+ return;
+ }
[self willChangeValueForKey:@"camera"];
+ _mbglMap->cancelTransitions();
+ mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:self.contentInset];
_mbglMap->easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
@@ -2577,20 +2746,11 @@ public:
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion
{
- self.userTrackingMode = MGLUserTrackingModeNone;
-
[self _flyToCamera:camera edgePadding:self.contentInset withDuration:duration peakAltitude:peakAltitude completionHandler:completion];
}
- (void)_flyToCamera:(MGLMapCamera *)camera edgePadding:(UIEdgeInsets)insets withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion
{
- _mbglMap->cancelTransitions();
- if ([self.camera isEqual:camera])
- {
- return;
- }
-
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets];
mbgl::AnimationOptions animationOptions;
if (duration >= 0)
{
@@ -2611,8 +2771,21 @@ public:
});
};
}
+
+ if ([self.camera isEqualToMapCamera:camera])
+ {
+ if (completion)
+ {
+ [self animateWithDelay:duration animations:^{
+ completion();
+ }];
+ }
+ return;
+ }
[self willChangeValueForKey:@"camera"];
+ _mbglMap->cancelTransitions();
+ mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera edgePadding:insets];
_mbglMap->flyTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
@@ -2634,7 +2807,7 @@ public:
{
CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : _mbglMap->getLatLng());
double zoomLevel = cameraOptions.zoom ? *cameraOptions.zoom : self.zoomLevel;
- CLLocationDirection direction = cameraOptions.angle ? -MGLDegreesFromRadians(*cameraOptions.angle) : self.direction;
+ CLLocationDirection direction = cameraOptions.angle ? mbgl::util::wrap(-MGLDegreesFromRadians(*cameraOptions.angle), 0., 360.) : self.direction;
CGFloat pitch = cameraOptions.pitch ? MGLDegreesFromRadians(*cameraOptions.pitch) : _mbglMap->getPitch();
CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoomLevel, pitch, centerCoordinate.latitude, self.frame.size);
return [MGLMapCamera cameraLookingAtCenterCoordinate:centerCoordinate fromDistance:altitude pitch:pitch heading:direction];
@@ -2855,12 +3028,12 @@ public:
{
return nil;
}
-
+
std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect];
if (annotationTags.size())
{
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()];
-
+
for (auto const& annotationTag: annotationTags)
{
if (!_annotationContextsByAnnotationTag.count(annotationTag))
@@ -2870,10 +3043,10 @@ public:
MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
[annotations addObject:annotationContext.annotation];
}
-
+
return [annotations copy];
}
-
+
return nil;
}
@@ -2897,7 +3070,7 @@ public:
{
return MGLAnnotationTagNotFound;
}
-
+
return _annotationTagsByAnnotation.at(annotation);
}
@@ -3111,6 +3284,11 @@ public:
if (annotationView)
{
+ // Make sure that the annotation views are selected/deselected correctly because
+ // annotations are not dismissed when they move out of the visible bounds
+ BOOL isViewForSelectedAnnotation = self.selectedAnnotation == annotation;
+ [annotationView setSelected:isViewForSelectedAnnotation];
+
annotationView.annotation = annotation;
annotationView.mapView = self;
CGRect bounds = UIEdgeInsetsInsetRect({ CGPointZero, annotationView.frame.size }, annotationView.alignmentRectInsets);
@@ -3869,14 +4047,13 @@ public:
{
self.locationManager = [[CLLocationManager alloc] init];
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([CLLocationManager instancesRespondToSelector:@selector(requestWhenInUseAuthorization)] && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
{
BOOL hasLocationDescription = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"];
if (!hasLocationDescription)
{
[NSException raise:@"Missing Location Services usage description" format:
- @"In iOS 8 and above, this app must have a value for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in its Info.plist."];
+ @"This app must have a value for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in its Info.plist."];
}
if ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
@@ -3888,7 +4065,6 @@ public:
[self.locationManager requestWhenInUseAuthorization];
}
}
-#endif
self.locationManager.headingFilter = 5.0;
self.locationManager.delegate = self;
@@ -4562,30 +4738,10 @@ public:
&& calloutView.dismissesAutomatically);
// dismissesAutomatically is an optional property and we want to dismiss
// the callout view if it's unimplemented.
- if (dismissesAutomatically || ![calloutView respondsToSelector:@selector(dismissesAutomatically)])
+ if (dismissesAutomatically || (calloutView && ![calloutView respondsToSelector:@selector(dismissesAutomatically)]))
{
[self deselectAnnotation:self.selectedAnnotation animated:NO];
}
- else
- {
- // Deselect annotation if it lies outside the viewport
- if (self.selectedAnnotation) {
- MGLAnnotationTag tag = [self annotationTagForAnnotation:self.selectedAnnotation];
- MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
- MGLAnnotationView *annotationView = annotationContext.annotationView;
-
- CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];
-
- if (annotationView)
- {
- rect = annotationView.frame;
- }
-
- if ( ! CGRectIntersectsRect(rect, self.frame)) {
- [self deselectAnnotation:self.selectedAnnotation animated:NO];
- }
- }
- }
}
if ( ! [self isSuppressingChangeDelimiters] && [self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)])
@@ -4729,11 +4885,11 @@ public:
CGFloat widthAdjustment = self.camera.pitch > 0.0 ? 0.0 : -_largestAnnotationViewSize.width * 2.0;
CGFloat heightAdjustment = self.camera.pitch > 0.0 ? 0.0 : -_largestAnnotationViewSize.height * 2.0;
CGRect viewPort = CGRectInset(self.bounds, widthAdjustment, heightAdjustment);
-
+
NSArray *visibleAnnotations = [self visibleAnnotationsInRect:viewPort];
NSMutableArray *offscreenAnnotations = [self.annotations mutableCopy];
[offscreenAnnotations removeObjectsInArray:visibleAnnotations];
-
+
// Update the center of visible annotation views
for (id<MGLAnnotation> annotation in visibleAnnotations)
{
@@ -4788,7 +4944,7 @@ public:
NSAssert(annotationTag != MGLAnnotationTagNotFound, @"-visibleAnnotationsInRect: returned unrecognized annotation");
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
UIView *annotationView = annotationContext.annotationView;
-
+
if (annotationView)
{
CLLocationCoordinate2D coordinate = annotation.coordinate;
@@ -4823,27 +4979,27 @@ public:
{
UIView <MGLCalloutView> *calloutView = self.calloutViewForSelectedAnnotation;
id <MGLAnnotation> annotation = calloutView.representedObject;
-
+
BOOL isAnchoredToAnnotation = (calloutView
&& annotation
&& [calloutView respondsToSelector:@selector(isAnchoredToAnnotation)]
&& calloutView.isAnchoredToAnnotation);
-
+
if (isAnchoredToAnnotation)
{
MGLAnnotationTag tag = [self annotationTagForAnnotation:annotation];
MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag);
MGLAnnotationView *annotationView = annotationContext.annotationView;
-
+
CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag];
-
+
if (annotationView)
{
rect = annotationView.frame;
}
-
+
CGPoint point = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
-
+
if ( ! CGPointEqualToPoint(calloutView.center, point)) {
calloutView.center = point;
}
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 09e2465a28..12320a63a5 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -24,10 +24,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view is about to
change.
-
+
This method is called whenever the currently displayed map camera will start
changing for any reason.
-
+
@param mapView The map view whose viewpoint will change.
@param animated Whether the change will cause an animated effect on the map.
*/
@@ -35,14 +35,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view is changing.
-
+
This method is called as the currently displayed map camera changes as part of
an animation, whether due to a user gesture or due to a call to a method such
as `-[MGLMapView setCamera:animated:]`. During the animation, this method may
be called many times to report updates to the viewpoint. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view whose viewpoint is changing.
*/
- (void)mapViewRegionIsChanging:(MGLMapView *)mapView;
@@ -50,33 +50,55 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view has finished
changing.
-
+
This method is called whenever the currently displayed map camera has finished
changing, after any calls to `-mapViewRegionIsChanging:` due to animation.
-
+
@param mapView The map view whose viewpoint has changed.
@param animated Whether the change caused an animated effect on the map.
*/
- (void)mapView:(MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated;
+/**
+ Asks the delegate whether the map view should be allowed to change from the
+ existing camera to the new camera in response to a user gesture.
+
+ This method is called as soon as the user gesture is recognized. It is not
+ called in response to a programmatic camera change, such as by setting the
+ `centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
+
+ This method is called many times during gesturing, so you should avoid performing
+ complex or performance-intensive tasks in your implementation.
+
+ @param mapView The map view that the user is manipulating.
+ @param oldCamera The camera representing the viewpoint at the moment the
+ gesture is recognized. If this method returns `NO`, the map view’s camera
+ continues to be this camera.
+ @param newCamera The expected camera after the gesture completes. If this
+ method returns `YES`, this camera becomes the map view’s camera.
+ @return A Boolean value indicating whether the map view should stay at
+ `oldCamera` or change to `newCamera`.
+ */
+- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera;
+
#pragma mark Loading the Map
/**
Tells the delegate that the map view will begin to load.
-
+
This method is called whenever the map view starts loading, including when a
new style has been set and the map must reload.
-
+
@param mapView The map view that is starting to load.
*/
- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
/**
Tells the delegate that the map view has finished loading.
-
+
This method is called whenever the map view finishes loading, either after the
initial load or after a style change has forced a reload.
-
+
@param mapView The map view that has finished loading.
*/
- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
@@ -84,11 +106,11 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view was unable to load data needed for
displaying the map.
-
+
This method may be called for a variety of reasons, including a network
connection failure or a failure to fetch the style from the server. You can use
the given error message to notify the user that map data is unavailable.
-
+
@param mapView The map view that is unable to load the data.
@param error The reason the data could not be loaded.
*/
@@ -102,39 +124,39 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view is about to redraw.
-
+
This method is called any time the map view needs to redraw due to a change in
the viewpoint or style property transition. This method may be called very
frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view that is about to redraw.
*/
- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
/**
Tells the delegate that the map view has just redrawn.
-
+
This method is called any time the map view needs to redraw due to a change in
the viewpoint or style property transition. This method may be called very
frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view that has just redrawn.
*/
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
/**
Tells the delegate that the map has just finished loading a style.
-
+
This method is called during the initialization of the map view and after any
subsequent loading of a new style. This method is called between the
`-mapViewWillStartRenderingMap:` and `-mapViewDidFinishRenderingMap:` delegate
methods. Changes to sources or layers of the current style do not cause this
method to be called.
-
+
This method is the earliest opportunity to modify the layout or appearance of
the current style before the map view is displayed to the user.
@@ -147,37 +169,37 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view will begin tracking the user’s location.
-
+
This method is called when the value of the `showsUserLocation` property
changes to `YES`.
-
+
@param mapView The map view that is tracking the user’s location.
*/
- (void)mapViewWillStartLocatingUser:(MGLMapView *)mapView;
/**
Tells the delegate that the map view has stopped tracking the user’s location.
-
+
This method is called when the value of the `showsUserLocation` property
changes to `NO`.
-
+
@param mapView The map view that is tracking the user’s location.
*/
- (void)mapViewDidStopLocatingUser:(MGLMapView *)mapView;
/**
Tells the delegate that the location of the user was updated.
-
+
While the `showsUserLocation` property is set to `YES`, this method is called
whenever a new location update is received by the map view. This method is also
called if the map view’s user tracking mode is set to
`MGLUserTrackingModeFollowWithHeading` and the heading changes, or if it is set
to `MGLUserTrackingModeFollowWithCourse` and the course changes.
-
+
This method is not called if the application is currently running in the
background. If you want to receive location updates while running in the
background, you must use the Core Location framework.
-
+
@param mapView The map view that is tracking the user’s location.
@param userLocation The location object representing the user’s latest
location. This property may be `nil`.
@@ -186,7 +208,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that an attempt to locate the user’s position failed.
-
+
@param mapView The map view that is tracking the user’s location.
@param error An error object containing the reason why location tracking
failed.
@@ -195,10 +217,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view’s user tracking mode has changed.
-
+
This method is called after the map view asynchronously changes to reflect the
new user tracking mode, for example by beginning to zoom or rotate.
-
+
@param mapView The map view that changed its tracking mode.
@param mode The new tracking mode.
@param animated Whether the change caused an animated effect on the map.
@@ -210,16 +232,16 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns an annotation image object to mark the given point annotation object on
the map.
-
+
Implement this method to mark a point annotation with a static image. If you
want to mark a particular point annotation with an annotation view instead,
omit this method or have it return `nil` for that annotation, then implement
`-mapView:viewForAnnotation:`.
-
+
Static annotation images use less memory and draw more quickly than annotation
views. On the other hand, annotation views are compatible with UIKit, Core
Animation, and other Cocoa Touch frameworks.
-
+
@param mapView The map view that requested the annotation image.
@param annotation The object representing the annotation that is about to be
displayed.
@@ -233,7 +255,7 @@ NS_ASSUME_NONNULL_BEGIN
A value of `0.0` results in a completely transparent shape. A value of `1.0`,
the default, results in a completely opaque shape.
-
+
This method sets the opacity of an entire shape, inclusive of its stroke and
fill. To independently set the values for stroke or fill, specify an alpha
component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or
@@ -247,13 +269,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the color to use when rendering the outline of a shape annotation.
-
+
The default stroke color is the map view’s tint color. If a pattern color is
specified, the result is undefined.
-
+
Opacity may be set by specifying an alpha component. The default alpha value is
`1.0` and results in a completely opaque stroke.
-
+
@param mapView The map view rendering the shape annotation.
@param annotation The annotation being rendered.
@return A color to use for the shape outline.
@@ -262,13 +284,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the color to use when rendering the fill of a polygon annotation.
-
+
The default fill color is the map view’s tint color. If a pattern color is
specified, the result is undefined.
-
+
Opacity may be set by specifying an alpha component. The default alpha value is
`1.0` and results in a completely opaque shape.
-
+
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
@return The polygon’s interior fill color.
@@ -278,9 +300,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the line width in points to use when rendering the outline of a
polyline annotation.
-
+
By default, the polyline is outlined with a line `3.0` points wide.
-
+
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
@return A line width for the polyline, measured in points.
@@ -291,16 +313,16 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a view object to mark the given point annotation object on the map.
-
+
Implement this method to mark a point annotation with a view object. If you
want to mark a particular point annotation with a static image instead, omit
this method or have it return `nil` for that annotation, then implement
`-mapView:imageForAnnotation:` instead.
-
+
Annotation views are compatible with UIKit, Core Animation, and other Cocoa
Touch frameworks. On the other hand, static annotation images use less memory
and draw more quickly than annotation views.
-
+
The user location annotation view can also be customized via this method. When
`annotation` is an instance of `MGLUserLocation` (or equal to the map view’s
`userLocation` property), return an instance of `MGLUserLocationAnnotationView`
@@ -317,10 +339,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one or more annotation views have been added and
positioned on the map.
-
+
This method is called just after the views are added to the map. You can
implement this method to animate the addition of the annotation views.
-
+
@param mapView The map view to which the annotation views were added.
@param annotationViews An array of `MGLAnnotationView` objects representing the
views that were added.
@@ -331,13 +353,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotations was selected.
-
+
You can use this method to track changes in the selection state of annotations.
-
+
If the annotation is associated with an annotation view, you can also implement
`-mapView:didSelectAnnotationView:`, which is called immediately after this
method is called.
-
+
@param mapView The map view containing the annotation.
@param annotation The annotation that was selected.
*/
@@ -345,13 +367,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotations was deselected.
-
+
You can use this method to track changes in the selection state of annotations.
-
+
If the annotation is associated with an annotation view, you can also implement
`-mapView:didDeselectAnnotationView:`, which is called immediately after this
method is called.
-
+
@param mapView The map view containing the annotation.
@param annotation The annotation that was deselected.
*/
@@ -359,15 +381,15 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotation views was selected.
-
+
You can use this method to track changes in the selection state of annotation
views.
-
+
This method is only called for annotation views. To track changes in the
selection state of all annotations, including those associated with static
annotation images, implement `-mapView:didSelectAnnotation:`, which is called
immediately before this method is called.
-
+
@param mapView The map view containing the annotation.
@param annotationView The annotation view that was selected.
*/
@@ -375,15 +397,15 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotation views was deselected.
-
+
You can use this method to track changes in the selection state of annotation
views.
-
+
This method is only called for annotation views. To track changes in the
selection state of all annotations, including those associated with static
annotation images, implement `-mapView:didDeselectAnnotation:`, which is called
immediately before this method is called.
-
+
@param mapView The map view containing the annotation.
@param annotationView The annotation view that was deselected.
*/
@@ -394,10 +416,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a Boolean value indicating whether the annotation is able to display
extra information in a callout bubble.
-
+
This method is called after an annotation is selected, before any callout is
displayed for the annotation.
-
+
If the return value is `YES`, a callout view is shown when the user taps on an
annotation, selecting it. The default callout displays the annotation’s title
and subtitle. You can add accessory views to either end of the callout by
@@ -405,11 +427,11 @@ NS_ASSUME_NONNULL_BEGIN
`-mapView:rightCalloutAccessoryViewForAnnotation:` methods. You can further
customize the callout’s contents by implementing the
`-mapView:calloutViewForAnnotation:` method.
-
+
If the return value is `NO`, or if this method is absent from the delegate, or
if the annotation lacks a title, the annotation will not show a callout even
when selected.
-
+
@param mapView The map view that has selected the annotation.
@param annotation The object representing the annotation.
@return A Boolean value indicating whether the annotation should show a
@@ -419,14 +441,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a callout view to display for the given annotation.
-
+
If this method is present in the delegate, it must return a new instance of a
view dedicated to display the callout. The returned view will be configured by
the map view.
-
+
If this method is absent from the delegate, or if it returns `nil`, a standard,
two-line, bubble-like callout view is displayed by default.
-
+
@param mapView The map view that requested the callout view.
@param annotation The object representing the annotation.
@return A view conforming to the `MGLCalloutView` protocol, or `nil` to use the
@@ -436,24 +458,24 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the view to display on the left side of the standard callout bubble.
-
+
The left callout view is typically used to convey information about the
annotation or to link to custom information provided by your application.
-
+
If the view you specify is a descendant of the `UIControl` class, you can use
the map view’s delegate to receive notifications when your control is tapped,
by implementing the `-mapView:annotation:calloutAccessoryControlTapped:`
method. If the view you specify does not descend from `UIControl`, your view is
responsible for handling any touch events within its bounds.
-
+
If this method is absent from the delegate, or if it returns `nil`, the
standard callout view has no accessory view on its left side. The return value
of this method is ignored if `-mapView:calloutViewForAnnotation:` is present in
the delegate.
-
+
To display a view on the callout’s right side, implement the
`-mapView:rightCalloutAccessoryViewForAnnotation:` method.
-
+
@param mapView The map view presenting the annotation callout.
@param annotation The object representing the annotation with the callout.
@return The accessory view to display.
@@ -462,24 +484,24 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the view to display on the right side of the standard callout bubble.
-
+
The right callout view is typically used to convey information about the
annotation or to link to custom information provided by your application.
-
+
If the view you specify is a descendant of the `UIControl` class, you can use
the map view’s delegate to receive notifications when your control is tapped,
by implementing the `-mapView:annotation:calloutAccessoryControlTapped:`
method. If the view you specify does not descend from `UIControl`, your view is
responsible for handling any touch events within its bounds.
-
+
If this method is absent from the delegate, or if it returns `nil`, the
standard callout view has no accessory view on its right side. The return value
of this method is ignored if `-mapView:calloutViewForAnnotation:` is present in
the delegate.
-
+
To display a view on the callout’s left side, implement the
`-mapView:leftCalloutAccessoryViewForAnnotation:` method.
-
+
@param mapView The map view presenting the annotation callout.
@param annotation The object representing the annotation with the callout.
@return The accessory view to display.
@@ -489,7 +511,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the user tapped one of the accessory controls in the
annotation’s callout view.
-
+
In a standard callout view, accessory views contain custom content and are
positioned on either side of the annotation title text. If an accessory view
you specify is a descendant of the `UIControl` class, the map view calls this
@@ -498,13 +520,13 @@ NS_ASSUME_NONNULL_BEGIN
For example, if your control displays additional information about the
annotation, you could use this method to present a modal panel with that
information.
-
+
If your custom accessory views are not descendants of the `UIControl` class,
the map view does not call this method. If the annotation has a custom callout
view via the `-mapView:calloutViewForAnnotation:` method, you can specify the
custom accessory views using the `MGLCalloutView` protocol’s
`leftAccessoryView` and `rightAccessoryView` properties.
-
+
@param mapView The map view containing the specified annotation.
@param annotation The annotation whose accessory view was tapped.
@param control The control that was tapped.
@@ -513,17 +535,17 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the user tapped on an annotation’s callout view.
-
+
This method is called when the user taps on the body of the callout view, as
opposed to the callout’s left or right accessory view. If the annotation has a
custom callout view via the `-mapView:calloutViewForAnnotation:` method, this
method is only called whenever the callout view calls its delegate’s
`-[MGLCalloutViewDelegate calloutViewTapped:]` method.
-
+
If this method is present on the delegate, the standard callout view’s body
momentarily highlights when the user taps it, whether or not this method does
anything in response to the tap.
-
+
@param mapView The map view containing the specified annotation.
@param annotation The annotation whose callout was tapped.
*/
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index 744b80047b..7b28ccf1a8 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -94,12 +94,12 @@ const NSTimeInterval MGLFlushInterval = 180;
- (NSString *)sysInfoByName:(char *)typeSpecifier {
size_t size;
sysctlbyname(typeSpecifier, NULL, &size, NULL, 0);
-
+
char *answer = malloc(size);
sysctlbyname(typeSpecifier, answer, &size, NULL, 0);
-
+
NSString *results = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
-
+
free(answer);
return results;
}
@@ -180,11 +180,11 @@ const NSTimeInterval MGLFlushInterval = 180;
// Events Control
_eventQueue = [[NSMutableArray alloc] init];
-
+
// Setup Date Format
_rfc3339DateFormatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
-
+
[_rfc3339DateFormatter setLocale:enUSPOSIXLocale];
[_rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
// Clear Any System TimeZone Cache
@@ -201,10 +201,10 @@ const NSTimeInterval MGLFlushInterval = 180;
} else {
self.canEnableDebugLogging = YES;
}
-
+
// Watch for changes to telemetry settings by the user
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil];
-
+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseOrResumeMetricsCollectionIfRequired) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseOrResumeMetricsCollectionIfRequired) name:UIApplicationDidBecomeActiveNotification object:nil];
@@ -256,11 +256,11 @@ const NSTimeInterval MGLFlushInterval = 180;
- (void)pauseOrResumeMetricsCollectionIfRequired {
UIApplication *application = [UIApplication sharedApplication];
-
+
// Prevent blue status bar when host app has `when in use` permission only and it is not in foreground
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse &&
application.applicationState == UIApplicationStateBackground) {
-
+
if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
_backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:_backgroundTaskIdentifier];
@@ -268,11 +268,11 @@ const NSTimeInterval MGLFlushInterval = 180;
}];
[self flush];
}
-
+
[self pauseMetricsCollection];
return;
}
-
+
// Toggle pause based on current pause state, user opt-out state, and low-power state.
BOOL enabled = [[self class] isEnabled];
if (self.paused && enabled) {
@@ -287,13 +287,13 @@ const NSTimeInterval MGLFlushInterval = 180;
if (self.paused) {
return;
}
-
+
self.paused = YES;
[self.timer invalidate];
self.timer = nil;
[self.eventQueue removeAllObjects];
self.data = nil;
-
+
[self.locationManager stopUpdatingLocation];
}
@@ -304,7 +304,7 @@ const NSTimeInterval MGLFlushInterval = 180;
self.paused = NO;
self.data = [[MGLMapboxEventsData alloc] init];
-
+
[self.locationManager startUpdatingLocation];
}
@@ -316,24 +316,24 @@ const NSTimeInterval MGLFlushInterval = 180;
if ([MGLAccountManager accessToken] == nil) {
return;
}
-
+
if ([self.eventQueue count] <= 1) {
[self.eventQueue removeAllObjects];
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
return;
}
-
+
NSArray *events = [NSArray arrayWithArray:self.eventQueue];
[self.eventQueue removeAllObjects];
-
+
[self postEvents:events];
-
+
if (self.timer) {
[self.timer invalidate];
self.timer = nil;
}
-
+
[self pushDebugEvent:MGLEventTypeLocalDebug withAttributes:@{MGLEventKeyLocalDebugDescription:@"flush"}];
}
@@ -341,21 +341,21 @@ const NSTimeInterval MGLFlushInterval = 180;
if (self.nextTurnstileSendDate && [[NSDate date] timeIntervalSinceDate:self.nextTurnstileSendDate] < 0) {
return;
}
-
+
NSString *vendorID = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
if (!vendorID) {
return;
}
-
+
NSDictionary *turnstileEventAttributes = @{MGLEventKeyEvent: MGLEventTypeAppUserTurnstile,
MGLEventKeyCreated: [self.rfc3339DateFormatter stringFromDate:[NSDate date]],
MGLEventKeyVendorID: vendorID,
MGLEventKeyEnabledTelemetry: @([[self class] isEnabled])};
-
+
if ([MGLAccountManager accessToken] == nil) {
return;
}
-
+
__weak __typeof__(self) weakSelf = self;
[self.apiClient postEvent:turnstileEventAttributes completionHandler:^(NSError * _Nullable error) {
__strong __typeof__(weakSelf) strongSelf = weakSelf;
@@ -375,7 +375,7 @@ const NSTimeInterval MGLFlushInterval = 180;
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;
NSDate *sometimeTomorrow = [calendar dateByAddingComponents:dayComponent toDate:[NSDate date] options:0];
-
+
// Find the start of tomorrow and use that as the next turnstile send date. The effect of this is that
// turnstile events can be sent as much as once per calendar day and always at the start of a session
// when a map load happens.
@@ -392,15 +392,15 @@ const NSTimeInterval MGLFlushInterval = 180;
if (!event) {
return;
}
-
+
if ([event isEqualToString:MGLEventTypeMapLoad]) {
[self pushTurnstileEvent];
}
-
+
if (self.paused) {
return;
}
-
+
MGLMapboxEventAttributes *fullyFormedEvent = [self fullyFormedEventForEvent:event withAttributes:attributeDictionary];
if (fullyFormedEvent) {
[self.eventQueue addObject:fullyFormedEvent];
@@ -497,7 +497,7 @@ const NSTimeInterval MGLFlushInterval = 180;
if (self.paused) {
return;
}
-
+
__weak __typeof__(self) weakSelf = self;
dispatch_async(self.serialQueue, ^{
__strong __typeof__(weakSelf) strongSelf = weakSelf;
@@ -553,7 +553,7 @@ const NSTimeInterval MGLFlushInterval = 180;
result = @"Default - Unknown";
break;
}
-
+
return result;
}
@@ -572,9 +572,9 @@ const NSTimeInterval MGLFlushInterval = 180;
- (NSInteger)contentSizeScale {
NSInteger result = -9999;
-
+
NSString *sc = [UIApplication sharedApplication].preferredContentSizeCategory;
-
+
if ([sc isEqualToString:UIContentSizeCategoryExtraSmall]) {
result = -3;
} else if ([sc isEqualToString:UIContentSizeCategorySmall]) {
@@ -600,7 +600,7 @@ const NSTimeInterval MGLFlushInterval = 180;
} else if ([sc isEqualToString:UIContentSizeCategoryAccessibilityExtraExtraExtraLarge]) {
result = 13;
}
-
+
return result;
}
@@ -675,18 +675,18 @@ const NSTimeInterval MGLFlushInterval = 180;
if (![self debugLoggingEnabled]) {
return;
}
-
+
if (!event) {
return;
}
-
+
MGLMutableMapboxEventAttributes *evt = [MGLMutableMapboxEventAttributes dictionaryWithDictionary:attributeDictionary];
[evt setObject:event forKey:@"event"];
[evt setObject:[self.rfc3339DateFormatter stringFromDate:[NSDate date]] forKey:@"created"];
[evt setValue:[self applicationState] forKey:@"applicationState"];
[evt setValue:@([[self class] isEnabled]) forKey:@"telemetryEnabled"];
[evt setObject:self.instanceID forKey:@"instance"];
-
+
MGLMapboxEventAttributes *finalEvent = [NSDictionary dictionaryWithDictionary:evt];
[self writeEventToLocalDebugLog:finalEvent];
}
@@ -713,12 +713,12 @@ const NSTimeInterval MGLFlushInterval = 180;
dispatch_async(self.debugLogSerialQueue, ^{
if ([NSJSONSerialization isValidJSONObject:event]) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:event options:NSJSONWritingPrettyPrinted error:nil];
-
+
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
jsonString = [jsonString stringByAppendingString:@",\n"];
-
+
NSString *logFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", self.dateForDebugLogFile]];
-
+
NSFileManager *fileManager = [[NSFileManager alloc] init];
if ([fileManager fileExistsAtPath:logFilePath]) {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
@@ -780,7 +780,7 @@ const NSTimeInterval MGLFlushInterval = 180;
if (mobileProvision[@"ProvisionedDevices"] && [mobileProvision[@"ProvisionedDevices"] count]) {
return NO; // development or ad-hoc
}
-
+
return YES; // expected development/enterprise/ad-hoc entitlements not found
#endif
}
diff --git a/platform/ios/src/MGLUserLocation.h b/platform/ios/src/MGLUserLocation.h
index 1a27d31dd4..c41c3ee7fd 100644
--- a/platform/ios/src/MGLUserLocation.h
+++ b/platform/ios/src/MGLUserLocation.h
@@ -23,7 +23,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, readonly, nullable) CLLocation *location;
-/**
+/**
A Boolean value indicating whether the user’s location is currently being
updated. (read-only)
*/
@@ -31,8 +31,8 @@ NS_ASSUME_NONNULL_BEGIN
/**
The heading of the user location. (read-only)
-
- This property is `nil` if the user location tracking mode is not
+
+ This property is `nil` if the user location tracking mode is not
`MGLUserTrackingModeFollowWithHeading`.
*/
@property (nonatomic, readonly, nullable) CLHeading *heading;
diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m
index 97e3f740fc..1c9649c09e 100644
--- a/platform/ios/src/MGLUserLocation.m
+++ b/platform/ios/src/MGLUserLocation.m
@@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_END
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLUserLocation class]]) return NO;
-
+
MGLUserLocation *otherUserLocation = other;
return ((!self.location && !otherUserLocation.location) || [self.location distanceFromLocation:otherUserLocation.location] == 0)
&& ((!self.title && !otherUserLocation.title) || [self.title isEqualToString:otherUserLocation.title])
diff --git a/platform/ios/src/MGLUserLocationAnnotationView.h b/platform/ios/src/MGLUserLocationAnnotationView.h
index bef18e9544..4b36236b8d 100644
--- a/platform/ios/src/MGLUserLocationAnnotationView.h
+++ b/platform/ios/src/MGLUserLocationAnnotationView.h
@@ -13,14 +13,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the associated map view.
-
+
The value of this property is nil during initialization.
*/
@property (nonatomic, readonly, weak, nullable) MGLMapView *mapView;
-
+
/**
Returns the annotation object indicating the user’s current location.
-
+
The value of this property is nil during initialization and while user tracking
is inactive.
*/
@@ -28,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the layer that should be used for annotation selection hit testing.
-
+
The default value of this property is the presentation layer of the view’s Core
Animation layer. When subclassing, you may override this property to specify a
different layer to be used for hit testing. This can be useful when you wish to
diff --git a/platform/ios/src/MGLUserLocationAnnotationView.m b/platform/ios/src/MGLUserLocationAnnotationView.m
index 3b8d976140..9795565050 100644
--- a/platform/ios/src/MGLUserLocationAnnotationView.m
+++ b/platform/ios/src/MGLUserLocationAnnotationView.m
@@ -22,12 +22,12 @@
{
self = [super initWithFrame:frame];
if (self == nil) return nil;
-
+
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitAdjustable | UIAccessibilityTraitUpdatesFrequently;
-
+
_accessibilityCoordinateFormatter = [[MGLCoordinateFormatter alloc] init];
_accessibilityCoordinateFormatter.unitStyle = NSFormattingUnitStyleLong;
-
+
return self;
}
@@ -57,13 +57,13 @@
{
return self.userLocation.subtitle;
}
-
+
// Each arcminute of longitude is at most about 1 nmi, too small for low zoom levels.
// Each arcsecond of longitude is at most about 30 m, too small for all but the very highest of zoom levels.
double zoomLevel = self.mapView.zoomLevel;
_accessibilityCoordinateFormatter.allowsMinutes = zoomLevel > 8;
_accessibilityCoordinateFormatter.allowsSeconds = zoomLevel > 20;
-
+
return [_accessibilityCoordinateFormatter stringFromCoordinate:self.mapView.centerCoordinate];
}
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 09ed100720..c9073f1674 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -16,6 +16,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLClockDirectionFormatter.h"
#import "MGLCompassDirectionFormatter.h"
#import "MGLCoordinateFormatter.h"
+#import "MGLDistanceFormatter.h"
#import "MGLFeature.h"
#import "MGLGeometry.h"
#import "MGLMapCamera.h"
diff --git a/platform/ios/src/UIImage+MGLAdditions.mm b/platform/ios/src/UIImage+MGLAdditions.mm
index 7b5737f5e4..d99a1f73ed 100644
--- a/platform/ios/src/UIImage+MGLAdditions.mm
+++ b/platform/ios/src/UIImage+MGLAdditions.mm
@@ -1,42 +1,31 @@
#import "UIImage+MGLAdditions.h"
+#include <mbgl/util/image+MGLAdditions.hpp>
+
@implementation UIImage (MGLAdditions)
- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage
{
- std::string png = encodePNG(spriteImage->image);
- NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
- if (self = [self initWithData:data scale:spriteImage->pixelRatio])
+ CGImageRef image = CGImageFromMGLPremultipliedImage(spriteImage->image.clone());
+ if (!image) {
+ return nil;
+ }
+
+ if (self = [self initWithCGImage:image scale:spriteImage->pixelRatio orientation:UIImageOrientationUp])
{
if (spriteImage->sdf)
{
self = [self imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
}
+ CGImageRelease(image);
return self;
}
-- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage
-{
- CGImageRef cgImage = self.CGImage;
- size_t width = CGImageGetWidth(cgImage);
- size_t height = CGImageGetHeight(cgImage);
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- mbgl::PremultipliedImage cPremultipliedImage({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
- size_t bytesPerPixel = 4;
- size_t bytesPerRow = bytesPerPixel * width;
- size_t bitsPerComponent = 8;
-
- CGContextRef context = CGBitmapContextCreate(cPremultipliedImage.data.get(),
- width, height, bitsPerComponent, bytesPerRow,
- colorSpace, kCGImageAlphaPremultipliedLast);
-
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgImage);
- CGContextRelease(context);
- CGColorSpaceRelease(colorSpace);
-
+- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage {
BOOL isTemplate = self.renderingMode == UIImageRenderingModeAlwaysTemplate;
- return std::make_unique<mbgl::SpriteImage>(std::move(cPremultipliedImage), float(self.scale), isTemplate);
+ return std::make_unique<mbgl::SpriteImage>(MGLPremultipliedImageFromCGImage(self.CGImage),
+ float(self.scale), isTemplate);
}
@end
diff --git a/platform/ios/test/MGLAnnotationViewTests.m b/platform/ios/test/MGLAnnotationViewTests.m
index 59f6956a95..212de9a405 100644
--- a/platform/ios/test/MGLAnnotationViewTests.m
+++ b/platform/ios/test/MGLAnnotationViewTests.m
@@ -74,7 +74,7 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
XCTAssertTrue(testCalloutView.didCallDismissCalloutAnimated, @"callout view was not dismissed");
[_mapView removeAnnotation:_annotationView.annotation];
-
+
XCTAssert(_mapView.annotations.count == 0, @"number of annotations should be 0");
XCTAssertNil(_annotationView.annotation, @"annotation property should be nil");
}
@@ -82,14 +82,14 @@ static NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReu
- (MGLAnnotationView *)mapView:(MGLMapView *)mapView viewForAnnotation:(id<MGLAnnotation>)annotation
{
MGLAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:MGLTestAnnotationReuseIdentifer];
-
+
if (!annotationView)
{
annotationView = [[MGLAnnotationView alloc] initWithReuseIdentifier:MGLTestAnnotationReuseIdentifer];
}
-
+
_annotationView = annotationView;
-
+
return annotationView;
}
diff --git a/platform/ios/test/MGLNSDataAdditionsTests.m b/platform/ios/test/MGLNSDataAdditionsTests.m
index b01db25812..8d145be4a0 100644
--- a/platform/ios/test/MGLNSDataAdditionsTests.m
+++ b/platform/ios/test/MGLNSDataAdditionsTests.m
@@ -10,28 +10,28 @@
- (void)testCompressDecompress
{
NSArray *originalArray = [self mockDataWithCount:180];
-
+
NSData *originalData = [NSJSONSerialization dataWithJSONObject:originalArray options:0 error:nil];
-
+
NSData *compressedData = [originalData mgl_compressedData];
NSData *decompressedData = [compressedData mgl_decompressedData];
-
+
NSArray *decompressedArray = [NSJSONSerialization JSONObjectWithData:decompressedData options:0 error:nil];
-
+
XCTAssertTrue([originalArray isEqualToArray:decompressedArray], @"originalArray and decompressedArray should be equal");
}
- (NSArray *)mockDataWithCount:(NSUInteger)count
{
NSMutableArray *array = [NSMutableArray array];
-
+
for (NSUInteger i=0;i<count;i++)
{
[array addObject:@{@"lat": @([self safeValueBetween:-90 and:90]),
@"lng": @([self safeValueBetween:-180 and:180]),
@"timestamp": @((floor([NSDate date].timeIntervalSince1970) * 100) / 100)}];
}
-
+
return array;
}
diff --git a/platform/ios/test/MGLSourceTests.m b/platform/ios/test/MGLSourceTests.m
index 90ec4e3a0b..2e4942cbe9 100644
--- a/platform/ios/test/MGLSourceTests.m
+++ b/platform/ios/test/MGLSourceTests.m
@@ -9,9 +9,9 @@
- (void)testDuplicateSources {
MGLVectorSource *source1 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
MGLVectorSource *source2 = [[MGLVectorSource alloc] initWithIdentifier:@"my-source" URL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]];
-
+
[self.mapView.style addSource: source1];
-
+
@try {
[self.mapView.style addSource: source2];
XCTFail(@"Should not have reached this point");
diff --git a/platform/ios/uitest/MapViewTests.m b/platform/ios/uitest/MapViewTests.m
index 41ea5446ef..4ed3d89399 100644
--- a/platform/ios/uitest/MapViewTests.m
+++ b/platform/ios/uitest/MapViewTests.m
@@ -155,7 +155,7 @@
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];
@@ -171,7 +171,7 @@
@"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];
@@ -181,7 +181,7 @@
@"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
@@ -220,7 +220,7 @@
- (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];
@@ -239,7 +239,7 @@
@"setting center coordinate should cancel transitions");
[cameraIsInDCExpectation fulfill];
});
-
+
[self waitForExpectationsWithTimeout:1.0 handler:nil];
}
@@ -260,7 +260,7 @@
@"disabling pan gesture should disallow horizontal panning");
}
-- (void)testRotate {
+- (void)testRotateClockwise {
CLLocationDirection startAngle = tester.mapView.direction;
XCTAssertNotEqual(startAngle,
@@ -274,6 +274,21 @@
@"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;
@@ -305,6 +320,23 @@
@"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];
@@ -404,20 +436,20 @@
- (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");
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMArg.h b/platform/ios/uitest/OCMock/OCMock/OCMArg.h
index d53437cb7d..2b5f9c7a4e 100644
--- a/platform/ios/uitest/OCMock/OCMock/OCMArg.h
+++ b/platform/ios/uitest/OCMock/OCMock/OCMArg.h
@@ -16,7 +16,7 @@
#import <Foundation/Foundation.h>
-@interface OCMArg : NSObject
+@interface OCMArg : NSObject
// constraining arguments
diff --git a/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h b/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h
index 777966ab7d..25aa8bf497 100644
--- a/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h
+++ b/platform/ios/uitest/OCMock/OCMock/OCMConstraint.h
@@ -17,7 +17,7 @@
#import <Foundation/Foundation.h>
-@interface OCMConstraint : NSObject
+@interface OCMConstraint : NSObject
+ (instancetype)constraint;
- (BOOL)evaluate:(id)value;
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
index f033c93a3f..e941b6daf9 100644
--- 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
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "0800"
+ LastUpgradeVersion = "0820"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/platform/ios/vendor/Fabric/Fabric+FABKits.h b/platform/ios/vendor/Fabric/Fabric+FABKits.h
index 05e9630210..bb576ab061 100644
--- a/platform/ios/vendor/Fabric/Fabric+FABKits.h
+++ b/platform/ios/vendor/Fabric/Fabric+FABKits.h
@@ -15,7 +15,7 @@
* The configuration information is parsed from the application's Info.plist. This
* method is primarily intended to be used by kits to retrieve their configuration.
*
- * @param kitClass The class of the kit whose configuration should be returned.
+ * @param kitClass The class of the kit whose configuration should be returned.
* It should conform to the FABKit protocol.
*
* @return A dictionary containing kit specific configuration information or nil if none exists.
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index dcd4692a18..b2366540ae 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -1,7 +1,5 @@
-mason_use(glfw VERSION 3.2.1)
-if(IS_CI_BUILD AND NOT WITH_EGL)
- mason_use(mesa VERSION 13.0.0${MASON_MESA_SUFFIX})
-endif()
+mason_use(glfw VERSION 2017-02-09-77a8f10)
+mason_use(mesa VERSION 13.0.4)
mason_use(boost_libprogram_options VERSION 1.62.0${MASON_CXXABI_SUFFIX})
mason_use(sqlite VERSION 3.14.2)
mason_use(libuv VERSION 1.9.1)
@@ -9,26 +7,28 @@ mason_use(nunicode VERSION 1.7.1)
mason_use(libpng VERSION 1.6.25)
mason_use(libjpeg-turbo VERSION 1.5.0)
mason_use(webp VERSION 0.5.1)
-mason_use(gtest VERSION 1.7.0${MASON_CXXABI_SUFFIX})
-mason_use(benchmark VERSION 1.0.0)
+mason_use(gtest VERSION 1.8.0${MASON_CXXABI_SUFFIX})
+mason_use(benchmark VERSION 1.0.0-1)
mason_use(icu VERSION 58.1)
include(cmake/loop-uv.cmake)
macro(mbgl_platform_core)
+ target_add_mason_package(mbgl-core PUBLIC mesa)
+
if(WITH_OSMESA)
target_sources(mbgl-core
PRIVATE platform/default/headless_backend_osmesa.cpp
PRIVATE platform/default/mbgl/gl/headless_display.cpp
)
- target_add_mason_package(mbgl-core PUBLIC mesa)
+ target_link_libraries(mbgl-core
+ PUBLIC -lOSMesa
+ )
elseif(WITH_EGL)
target_sources(mbgl-core
PRIVATE platform/linux/src/headless_backend_egl.cpp
PRIVATE platform/linux/src/headless_display_egl.cpp
)
- # TODO: Provide surface-less EGL mesa for CI builds.
- # https://github.com/mapbox/mapbox-gl-native/issues/7020
target_link_libraries(mbgl-core
PUBLIC -lGLESv2
PUBLIC -lEGL
@@ -39,15 +39,10 @@ macro(mbgl_platform_core)
PRIVATE platform/linux/src/headless_backend_glx.cpp
PRIVATE platform/linux/src/headless_display_glx.cpp
)
- if (IS_CI_BUILD)
- target_add_mason_package(mbgl-core PUBLIC mesa)
- target_link_libraries(mbgl-core PUBLIC -lX11)
- else()
- target_link_libraries(mbgl-core
- PUBLIC -lGL
- PUBLIC -lX11
- )
- endif()
+ target_link_libraries(mbgl-core
+ PUBLIC -lGL
+ PUBLIC -lX11
+ )
endif()
target_sources(mbgl-core
@@ -77,6 +72,7 @@ macro(mbgl_platform_core)
# Image handling
PRIVATE platform/default/image.cpp
PRIVATE platform/default/jpeg_reader.cpp
+ PRIVATE platform/default/png_writer.cpp
PRIVATE platform/default/png_reader.cpp
PRIVATE platform/default/webp_reader.cpp
@@ -114,6 +110,13 @@ macro(mbgl_platform_glfw)
target_link_libraries(mbgl-glfw
PRIVATE mbgl-loop
)
+
+ add_custom_command(
+ TARGET mbgl-glfw POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${CMAKE_SOURCE_DIR}/common/ca-bundle.crt
+ ${CMAKE_CURRENT_BINARY_DIR}/ca-bundle.crt
+ )
endmacro()
diff --git a/platform/linux/scripts/coveralls.sh b/platform/linux/scripts/coveralls.sh
index 8d5903de6c..b8ab73a24e 100755
--- a/platform/linux/scripts/coveralls.sh
+++ b/platform/linux/scripts/coveralls.sh
@@ -3,12 +3,9 @@
set -e
set -o pipefail
-mapbox_time "install_lcov" \
-mason install lcov 1.12
-
# Collect coverage data and save it into coverage.info
mapbox_time "lcov_capture" \
-`mason prefix lcov 1.12`/usr/bin/lcov \
+`scripts/mason.sh PREFIX lcov VERSION 1.12`/usr/bin/lcov \
--quiet \
--capture \
--no-external \
diff --git a/platform/linux/src/headless_backend_egl.cpp b/platform/linux/src/headless_backend_egl.cpp
index 87e7c1d0ed..df0ecc8dff 100644
--- a/platform/linux/src/headless_backend_egl.cpp
+++ b/platform/linux/src/headless_backend_egl.cpp
@@ -31,9 +31,6 @@ struct EGLImpl : public HeadlessBackend::Impl {
}
~EGLImpl() {
- if (glContext != eglGetCurrentContext()) {
- activateContext();
- }
if (!eglDestroyContext(display, glContext)) {
throw std::runtime_error("Failed to destroy EGL context.\n");
}
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 90387cfdea..5015ee0819 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -6,10 +6,12 @@
* Added support for right-to-left text and Arabic ligatures in labels. ([#6984](https://github.com/mapbox/mapbox-gl-native/pull/6984), [#7123](https://github.com/mapbox/mapbox-gl-native/pull/7123))
* Improved the line wrapping behavior of point-placed labels, especially labels written in Chinese and Japanese. ([#6828](https://github.com/mapbox/mapbox-gl-native/pull/6828), [#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446))
-* Added a Simplified Chinese localization. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7503](https://github.com/mapbox/mapbox-gl-native/pull/7503))
+* CJK characters now remain upright in vertically oriented labels that have line placement, such as road labels. ([#7114](https://github.com/mapbox/mapbox-gl-native/issues/7114))
+* Added Chinese (Simplified and Traditional), French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7503](https://github.com/mapbox/mapbox-gl-native/pull/7503), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999))
### Styles
+* Added support for data-driven styling in the form of source and composite style functions. `MGLStyleFunction` is now an abstract class, with `MGLCameraStyleFunction` providing the behavior of `MGLStyleFunction` in previous releases. New `MGLStyleFunction` subclasses allow you to vary a style attribute by the values of attributes of features in the source. ([#7596](https://github.com/mapbox/mapbox-gl-native/pull/7596))
* Added `circleStrokeColor`, `circleStrokeWidth`, and `circleStrokeOpacity` properties to MGLCircleStyleLayer and support for corresponding properties in style JSON files. ([#7356](https://github.com/mapbox/mapbox-gl-native/pull/7356))
* Point-placed labels in symbol style layers are now placed at more optimal locations within polygons. ([#7465](https://github.com/mapbox/mapbox-gl-native/pull/7465))
* Fixed flickering that occurred when manipulating a style layer. ([#7616](https://github.com/mapbox/mapbox-gl-native/pull/7616))
@@ -19,15 +21,46 @@
* Fixed incorrect interpolation of style functions in Boolean-typed style attributes. ([#7526](https://github.com/mapbox/mapbox-gl-native/pull/7526))
* Removed support for the `ref` property in layers in style JSON files. ([#7586](https://github.com/mapbox/mapbox-gl-native/pull/7586))
* Fixed an issue that collapsed consecutive newlines within text labels. ([#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446))
+* Fixed artifacts when drawing particularly acute line joins. ([#7786](https://github.com/mapbox/mapbox-gl-native/pull/7786))
+* Fixed an issue in which a vector style layer predicate involving the `$id` key path would exclude all features from the layer. ([#7989](https://github.com/mapbox/mapbox-gl-native/pull/7989), [#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971))
+* Fixed an issue causing vector style layer predicates to be evaluated as if each feature had a `$type` attribute of 1, 2, or 3. The `$type` key path can now be compared to `Point`, `LineString`, or `Polygon`, as described in the documentation. ([#7971](https://github.com/mapbox/mapbox-gl-native/pull/7971))
+* When setting an `MGLShapeSource`’s shape to an `MGLFeature` instance, any `NSColor` attribute value is now converted to the equivalent CSS string representation for use with `MGLInterpolationModeIdentity` in style functions. ([#8025](https://github.com/mapbox/mapbox-gl-native/pull/8025))
+* An exception is no longer thrown if layers or sources are removed from a style before they are added. ([#7962](https://github.com/mapbox/mapbox-gl-native/pull/7962))
* Added `MGLComputedShapeSource` source class that allows applications to supply vector data on a per-tile basis.
+### User interaction
+
+* Added a method to MGLMapViewDelegate, `-mapView:shouldChangeFromCamera:toCamera:`, that you can implement to restrict which parts the user can navigate to using gestures. ([#5584](https://github.com/mapbox/mapbox-gl-native/pull/5584))
+* When a map view is the first responder, pressing <kbd>+</kbd>, <kbd>-</kbd>, or <kbd>=</kbd> now zooms the map. ([#8033](https://github.com/mapbox/mapbox-gl-native/pull/8033))
+* Zooming by double-tap, two-finger tap, zoom buttons, shortcut keys, or demo app menu items or shortcut keys now zooms to the nearest integer zoom level. ([#8027](https://github.com/mapbox/mapbox-gl-native/pull/8027))
+
+### Networking and offline maps
+
+* Offline pack notifications are now posted by `MGLOfflinePack` instances instead of the shared `MGLOfflineStorage` object. For backwards compatibility, the `userInfo` dictionary still indicates the pack’s state and progress. ([#7952](https://github.com/mapbox/mapbox-gl-native/pull/7952))
+* Fixed a memory leak in MGLMapView. ([#7956](https://github.com/mapbox/mapbox-gl-native/pull/7956))
+* Fixed an issue that could prevent a cached style from appearing while the computer is offline. ([#7770](https://github.com/mapbox/mapbox-gl-native/pull/7770))
+* Fixed an issue that could prevent a style from loading when reestablishing a network connection. ([#7902](https://github.com/mapbox/mapbox-gl-native/pull/7902))
+* `MGLOfflineStorage` instances now support a delegate conforming to `MGLOfflineStorageDelegate`, which allows altering URLs before they are requested from the internet. ([#8084](https://github.com/mapbox/mapbox-gl-native/pull/8084))
+
### Other changes
+* Fixed an issue that, among other things, caused various islands to disappear at certain zoom levels. ([#7621](https://github.com/mapbox/mapbox-gl-native/pull/7621))
* Fixed an issue where translucent point annotations along tile boundaries would be drawn darker than expected. ([#6832](https://github.com/mapbox/mapbox-gl-native/pull/6832))
* Fixed flickering that occurred when panning past the antimeridian. ([#7574](https://github.com/mapbox/mapbox-gl-native/pull/7574))
-* Fixed an issue that could prevent a cached style from appearing while the computer is offline. ([#7770](https://github.com/mapbox/mapbox-gl-native/pull/7770))
+* Added a `MGLDistanceFormatter` class for formatting geographic distances. ([#7888](https://github.com/mapbox/mapbox-gl-native/pull/7888))
+
+## 0.3.1 - February 21, 2017
+
+This version of the Mapbox macOS SDK corresponds to version 3.4.2 of the Mapbox iOS SDK.
+
+* Fixed an issue causing MGLMapView’s `camera`’s `heading` to be set to a negative value, indicating an undefined heading, when the map view faces northwest. The heading is now wrapped to between zero and 360 degrees, for consistency with MGLMapView’s `direction` property. ([#7724](https://github.com/mapbox/mapbox-gl-native/pull/7724))
+* Fixed a crash that occurred when moving a window containing an MGLMapView from one screen to another. ([#8004](https://github.com/mapbox/mapbox-gl-native/pull/8004))
+* Fixed an issue preventing the use of the integrated GPU on machines that have more than one GPU. Follow the instructions in [Technical Q&A 1734](https://developer.apple.com/library/content/qa/qa1734/_index.html) to enable integrated GPU usage in your application. ([#7834](https://github.com/mapbox/mapbox-gl-native/pull/7834))
+* Fixed an issue causing the mouse cursor to jump after shift- or option-dragging a map view if the window opened on a screen with a different size than the screen with keyboard focus. ([#7846](https://github.com/mapbox/mapbox-gl-native/pull/7846))
+* Deprecated the style class methods in MGLStyle. ([#7785](https://github.com/mapbox/mapbox-gl-native/pull/7785))
+* Improved the performance of trivial camera animations. ([#7125](https://github.com/mapbox/mapbox-gl-native/pull/7125))
-## 0.3.0
+## 0.3.0 - January 21, 2016
This version of the Mapbox macOS SDK corresponds to version 3.4.0 of the Mapbox iOS SDK. The two SDKs have very similar feature sets. The main differences are the lack of user location tracking and annotation views. Some APIs have been adapted to macOS conventions, particularly the use of NSPopover for callout views.
@@ -64,7 +97,8 @@ This version of the Mapbox macOS SDK corresponds to version 3.4.0 of the Mapbox
* Added `showAnnotations:animated:` and `showAnnotations:edgePadding:animated:`, which moves the map viewport to show the specified annotations. ([#5749](https://github.com/mapbox/mapbox-gl-native/pull/5749))
* Added new methods to MGLMultiPoint for changing the vertices along a polyline annotation or the exterior of a polygon annotation. ([#6565](https://github.com/mapbox/mapbox-gl-native/pull/6565))
-* Added new APIs to MGLMapView to query for visible annotations. ([6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
+* Fixed an exception raised when adding a custom annotation model object to MGLMapView. ([#7746](https://github.com/mapbox/mapbox-gl-native/pull/7746))
+* Added new APIs to MGLMapView to query for visible annotations. ([#6061](https://github.com/mapbox/mapbox-gl-native/pull/6061))
* Shape, feature, and annotation classes now conform to NSSecureCoding. ([#6559](https://github.com/mapbox/mapbox-gl-native/pull/6559))
* Various method arguments that are represented as C arrays of `CLLocationCoordinate2D` instances have been marked `const` to streamline bridging to Swift. ([#7215](https://github.com/mapbox/mapbox-gl-native/pull/7215))
* To make an MGLPolyline or MGLPolygon span the antimeridian, specify coordinates with longitudes greater than 180° or less than −180°. ([#6088](https://github.com/mapbox/mapbox-gl-native/pull/6088))
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index 6737566a5c..bc91e69456 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -89,12 +89,25 @@ To add or update text that the user may see in the macOS SDK:
### Adding a localization
-To add a localization to the macOS SDK:
+Translations of all the Mapbox GL Native SDKs are managed [in Transifex](https://www.transifex.com/mapbox/mapbox-gl-native/). If your language already has a translation, feel free to complete or proofread it. Otherwise, please [request your language](https://www.transifex.com/mapbox/mapbox-gl-native/languages/). Note that we’re primarily interested in languages that macOS supports as system languages.
+
+Once you’ve finished translating the SDK into a new language in Transifex, perform these steps to make Xcode aware of the translation:
1. In macos.xcworkspace, open the project editor for macos.xcodeproj. Using the project editor’s sidebar or tab bar dropdown, go to the “macos” project; under the Localizations section of the Info tab, click the + button to add your language to the project.
-1. In the sheet that appears, select all the .strings and .stringsdict files but no .xib file. (Most of the XIBs are part of the macosapp example application, which is not localized, while MGLAnnotationCallout.xib contains no localizable strings.)
-1. In the Project navigator, expand each .strings and .stringsdict file in the project. An additional version for your localization should be listed; translate it. Translate everything on the right side of the equals sign. Leave the left side and any comments unmodified. See Apple’s documentation on the [.strings](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/LoadingResources/Strings/Strings.html) and [.stringsdict](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html) formats.
-1. You’re already most of the way towards localizing the iOS SDK too – consider [completing that localization](../ios/DEVELOPING.md#adding-a-localization).
+1. In the sheet that appears, select all the .strings and .stringsdict files but no .xib file. (Most of the XIBs are part of the macosapp example application, which is not localized, while MGLAnnotationCallout.xib contains no localizable strings.) If your language lacks declension and pluralization, as in the case of Chinese, omit the .stringsdict files.
+1. In the Project navigator, expand each .stringsdict file in the project. An additional version for your localization should be listed; translate it. See Apple’s documentation on the [.stringsdict format](https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html).
+1. In the Project navigator, select Demo App/Localizable.strings and then, in the File Inspector, check the box for your new localization.
+1. Repeat the steps above in ios.xcworkspace.
+
+The .strings files should still be in the original English – that’s expected. Now you can pull your translations into this repository:
+
+1. _(First time only.)_ Download the [`tx` command line tool](https://docs.transifex.com/client/installing-the-client) and [configure your .transifexrc](https://docs.transifex.com/client/client-configuration).
+1. Run `tx pull -a`.
+1. Convert any added .strings files from UTF-16 encoding to UTF-8 encoding to facilitate diffing and merging. You can convert the file encoding using Xcode’s File inspector or the following command (substituting _MYLANG_ for the locale code):
+
+```
+find platform/{darwin,ios}/resources platform/macos/sdk -path '*/MYLANG.lproj/*.strings' -exec textutil -convert txt -extension strings -inputencoding UTF-16 -encoding UTF-8 {} -output {} \;
+```
### Adding a code example
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index f8b4c675de..ef04267c47 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -1,14 +1,14 @@
-# Integrating the Mapbox macOS SDK into your application
+# Integrating a custom build of the Mapbox macOS SDK into your application
-This document explains how to build the Mapbox macOS SDK and integrate it into your own Cocoa application.
+This document explains how to build a development version of the Mapbox macOS SDK from source and integrate it into your own Cocoa application. This process is for advanced developers who want to get a glimpse of the SDK’s development between releases. To use a production-ready version of the SDK, see the [Mapbox macOS SDK homepage](https://mapbox.github.io/mapbox-gl-native/macos/).
### Requirements
The Mapbox macOS SDK requires the macOS 10.10.0 SDK (or above) and Xcode 7.3 (or above).
-### Building the SDK
+### Building the SDK from source
-Grab a [prebuilt release](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “macos-” – or build the SDK from source:
+To build the SDK from source:
1. [Install core dependencies](../../INSTALL.md).
diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
index 6de7f829a3..c17e665512 100644
--- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec
+++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '0.3.0-rc.1'
+ version = '0.3.1'
m.name = 'Mapbox-macOS-SDK-symbols'
m.version = "#{version}-symbols"
diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec
index 03ef0eabe7..a6f2d2838b 100644
--- a/platform/macos/Mapbox-macOS-SDK.podspec
+++ b/platform/macos/Mapbox-macOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '0.3.0-rc.1'
+ version = '0.3.1'
m.name = 'Mapbox-macOS-SDK'
m.version = version
diff --git a/platform/macos/README.md b/platform/macos/README.md
index aea5ba0d6a..14b3e0cf16 100644
--- a/platform/macos/README.md
+++ b/platform/macos/README.md
@@ -1,10 +1,10 @@
-# Mapbox macOS SDK
+# [Mapbox macOS SDK](https://mapbox.github.io/mapbox-gl-native/macos/)
[![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd)
Put interactive, scalable world maps into your native Cocoa application with the Mapbox macOS SDK.
-* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
+* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [OpenStreetMap-based](https://www.mapbox.com/vector-tiles/mapbox-streets-v7/) [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
* Customize every aspect of the map’s appearance in code or visually using [Mapbox Studio](https://www.mapbox.com/mapbox-studio/).
* High-performance OpenGL rendering and multitouch gestures keep your users happy.
* A well-designed, fully documented API helps you stay productive.
@@ -14,11 +14,17 @@ Put interactive, scalable world maps into your native Cocoa application with the
The Mapbox macOS SDK 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://github.com/mapbox/mapbox-gl-js/).
-* [Integrate the Mapbox macOS SDK into your application](INSTALL.md)
+Information for Mac developers:
+
+* [Integrate the Mapbox macOS SDK into your application](https://mapbox.github.io/mapbox-gl-native/macos/)
+* [Learn how to use the Mapbox macOS SDK](https://mapbox.github.io/mapbox-gl-native/macos/)
+* [Browse example styles designed in Mapbox Studio](https://www.mapbox.com/gallery/)
+
+Information for contributors:
+
+* [Build the Mapbox macOS SDK from source](INSTALL.md)
* [Contribute to the Mapbox macOS SDK](DEVELOPING.md)
-* [Mapbox macOS SDK reference documentation](https://mapbox.github.io/mapbox-gl-native/macos/)
-* [See example styles designed in Mapbox Studio](https://www.mapbox.com/gallery/)
-* [Hand-authoring a macOS SDK–compatible style](https://www.mapbox.com/mapbox-gl-style-spec/)
+* [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/)
* [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/)
Mapbox does not officially support the Mapbox macOS SDK to the same extent as the Mapbox iOS SDK; however, bug reports and pull requests are certainly welcome.
diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m
index d3fe2d204e..0d780424f9 100644
--- a/platform/macos/app/AppDelegate.m
+++ b/platform/macos/app/AppDelegate.m
@@ -20,10 +20,10 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
switch (self.state) {
case MGLOfflinePackStateComplete:
return [NSImage imageNamed:@"NSMenuOnStateTemplate"];
-
+
case MGLOfflinePackStateActive:
return [NSImage imageNamed:@"NSFollowLinkFreestandingTemplate"];
-
+
default:
return nil;
}
@@ -71,7 +71,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
@end
-@interface AppDelegate ()
+@interface AppDelegate () <NSWindowDelegate>
@property (weak) IBOutlet NSArrayController *offlinePacksArrayController;
@property (weak) IBOutlet NSPanel *offlinePacksPanel;
@@ -104,7 +104,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
-
+
if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) {
NSData *cameraData = [[NSUserDefaults standardUserDefaults] objectForKey:MGLLastMapCameraDefaultsKey];
if (cameraData) {
@@ -130,7 +130,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
[alert runModal];
[self showPreferences:nil];
}
-
+
[self.offlinePacksArrayController bind:@"content" toObject:[MGLOfflineStorage sharedOfflineStorage] withKeyPath:@"packs" options:nil];
}
@@ -148,7 +148,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
[[NSUserDefaults standardUserDefaults] setInteger:mapView.debugMask forKey:MGLLastMapDebugMaskDefaultsKey];
}
}
-
+
[self.offlinePacksArrayController unbind:@"content"];
}
@@ -164,16 +164,16 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
}
-
+
MGLMapCamera *camera = [MGLMapCamera camera];
NSString *zoomLevelString = params[@"zoom"];
self.pendingZoomLevel = zoomLevelString.length ? zoomLevelString.doubleValue : -1;
-
+
NSString *directionString = params[@"bearing"];
if (directionString.length) {
camera.heading = directionString.doubleValue;
}
-
+
NSString *centerString = params[@"center"];
if (centerString) {
NSArray *coordinateValues = [centerString componentsSeparatedByString:@","];
@@ -182,12 +182,12 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
[coordinateValues[1] doubleValue]);
}
}
-
+
NSString *pitchString = params[@"pitch"];
if (pitchString.length) {
camera.pitch = pitchString.doubleValue;
}
-
+
self.pendingCamera = camera;
[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:NULL];
}
@@ -196,7 +196,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
- (IBAction)showOfflinePacksPanel:(id)sender {
[self.offlinePacksPanel makeKeyAndOrderFront:sender];
-
+
for (MGLOfflinePack *pack in self.offlinePacksArrayController.arrangedObjects) {
[pack requestProgress];
}
@@ -226,15 +226,15 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
}
break;
}
-
+
case MGLOfflinePackStateInactive:
[pack resume];
break;
-
+
case MGLOfflinePackStateActive:
[pack suspend];
break;
-
+
default:
break;
}
@@ -261,6 +261,14 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
[self.preferencesWindow makeKeyAndOrderFront:sender];
}
+- (IBAction)print:(id)sender {
+ NSDocument *currentDocument = [NSDocumentController sharedDocumentController].currentDocument;
+ if ([currentDocument isKindOfClass:[MapDocument class]]) {
+ MGLMapView *mapView = [(MapDocument *)currentDocument mapView];
+ [mapView print:sender];
+ }
+}
+
- (IBAction)openAccessTokenManager:(id)sender {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.mapbox.com/studio/account/tokens/"]];
}
@@ -277,10 +285,22 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
if (menuItem.action == @selector(showOfflinePacksPanel:)) {
return YES;
}
+ if (menuItem.action == @selector(print:)) {
+ return YES;
+ }
if (menuItem.action == @selector(delete:)) {
return self.offlinePacksArrayController.selectedObjects.count;
}
return NO;
}
+#pragma mark NSWindowDelegate methods
+
+- (void)windowWillClose:(NSNotification *)notification {
+ NSWindow *window = notification.object;
+ if (window == self.preferencesWindow) {
+ [window makeFirstResponder:nil];
+ }
+}
+
@end
diff --git a/platform/macos/app/Base.lproj/Localizable.strings b/platform/macos/app/Base.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/Base.lproj/Localizable.strings
diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib
index bc2ef06ef6..4f524df4d4 100644
--- a/platform/macos/app/Base.lproj/MainMenu.xib
+++ b/platform/macos/app/Base.lproj/MainMenu.xib
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11191" systemVersion="15G31" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1217" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11191"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -135,7 +136,7 @@
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
<connections>
- <action selector="print:" target="-1" id="qaZ-4w-aoO"/>
+ <action selector="print:" target="Voe-Tx-rLC" id="rXg-Pd-AG8"/>
</connections>
</menuItem>
</items>
@@ -709,6 +710,7 @@ CA
</constraints>
</view>
<connections>
+ <outlet property="delegate" destination="Voe-Tx-rLC" id="PNO-Pp-jOX"/>
<outlet property="initialFirstResponder" destination="7sb-sf-oJU" id="UZe-di-dnA"/>
</connections>
<point key="canvasLocation" x="754" y="221"/>
diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib
index 4ba8f0a3ad..b658b52cc2 100644
--- a/platform/macos/app/Base.lproj/MapDocument.xib
+++ b/platform/macos/app/Base.lproj/MapDocument.xib
@@ -1,7 +1,8 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11201" systemVersion="15G1004" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11201"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MapDocument">
@@ -47,7 +48,7 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="388" y="211" width="642" height="480"/>
- <rect key="screenRect" x="0.0" y="0.0" width="1280" height="777"/>
+ <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
<view key="contentView" id="TuG-C5-zLS">
<rect key="frame" x="0.0" y="0.0" width="642" height="480"/>
<autoresizingMask key="autoresizingMask"/>
@@ -123,7 +124,7 @@
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="185" id="VQs-2Z-hmP"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="NDx-rn-TLj">
- <rect key="frame" x="0.0" y="464" width="184.5" height="16"/>
+ <rect key="frame" x="0.0" y="464" width="163" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="0vt-rI-sHB">
diff --git a/platform/macos/app/DroppedPinAnnotation.m b/platform/macos/app/DroppedPinAnnotation.m
index 5b19fd7401..d7bd4068dc 100644
--- a/platform/macos/app/DroppedPinAnnotation.m
+++ b/platform/macos/app/DroppedPinAnnotation.m
@@ -11,7 +11,7 @@ static MGLCoordinateFormatter *DroppedPinCoordinateFormatter;
NSTimer *_timer;
NSTimeInterval _priorShownTimeInterval;
NSDate *_dateShown;
-
+
NSValueTransformer *_timeIntervalTransformer;
}
diff --git a/platform/macos/app/Info.plist b/platform/macos/app/Info.plist
index cc7037f589..21b86bfc75 100644
--- a/platform/macos/app/Info.plist
+++ b/platform/macos/app/Info.plist
@@ -52,5 +52,7 @@
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
</dict>
</plist>
diff --git a/platform/macos/app/LimeGreenStyleLayer.m b/platform/macos/app/LimeGreenStyleLayer.m
index 0d2e642db9..40c336cd98 100644
--- a/platform/macos/app/LimeGreenStyleLayer.m
+++ b/platform/macos/app/LimeGreenStyleLayer.m
@@ -14,11 +14,11 @@
- (void)didMoveToMapView:(MGLMapView *)mapView {
static const GLchar *vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }";
static const GLchar *fragmentShaderSource = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
-
+
_program = glCreateProgram();
_vertexShader = glCreateShader(GL_VERTEX_SHADER);
_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
-
+
glShaderSource(_vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(_vertexShader);
glAttachShader(_program, _vertexShader);
@@ -27,7 +27,7 @@
glAttachShader(_program, _fragmentShader);
glLinkProgram(_program);
_aPos = glGetAttribLocation(_program, "a_pos");
-
+
GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 };
glGenBuffers(1, &_buffer);
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
@@ -48,7 +48,7 @@
if (!_program) {
return;
}
-
+
glDeleteBuffers(1, &_buffer);
glDetachShader(_program, _vertexShader);
glDetachShader(_program, _fragmentShader);
diff --git a/platform/macos/app/MGLVectorSource+MBXAdditions.m b/platform/macos/app/MGLVectorSource+MBXAdditions.m
index f59b72aa9f..644b43a651 100644
--- a/platform/macos/app/MGLVectorSource+MBXAdditions.m
+++ b/platform/macos/app/MGLVectorSource+MBXAdditions.m
@@ -35,7 +35,7 @@
if (!self.mapboxStreets) {
return @{};
}
-
+
// Replace {name} and {name_*} with the matching localized name tag.
NSString *localizedKey = preferredLanguage ? [NSString stringWithFormat:@"name_%@", preferredLanguage] : @"name";
NSMutableDictionary *localizedKeysByKey = [NSMutableDictionary dictionaryWithObject:localizedKey forKey:@"name"];
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index dd1e4c2162..5913e7300d 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -22,10 +22,13 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSMutableArray *flattenedShapes = [NSMutableArray arrayWithCapacity:shapes.count];
for (id <MGLAnnotation> shape in shapes) {
NSArray *subshapes;
- // Flatten multipoints but not polylines or polygons.
- if ([shape isMemberOfClass:[MGLMultiPoint class]]) {
- NSUInteger pointCount = [(MGLMultiPoint *)shape pointCount];
- CLLocationCoordinate2D *coordinates = [(MGLMultiPoint *)shape coordinates];
+ if ([shape isKindOfClass:[MGLMultiPolyline class]]) {
+ subshapes = [(MGLMultiPolyline *)shape polylines];
+ } else if ([shape isKindOfClass:[MGLMultiPolygon class]]) {
+ subshapes = [(MGLMultiPolygon *)shape polygons];
+ } else if ([shape isKindOfClass:[MGLPointCollection class]]) {
+ NSUInteger pointCount = [(MGLPointCollection *)shape pointCount];
+ CLLocationCoordinate2D *coordinates = [(MGLPointCollection *)shape coordinates];
NSMutableArray *pointAnnotations = [NSMutableArray arrayWithCapacity:pointCount];
for (NSUInteger i = 0; i < pointCount; i++) {
MGLPointAnnotation *pointAnnotation = [[MGLPointAnnotation alloc] init];
@@ -33,14 +36,10 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[pointAnnotations addObject:pointAnnotation];
}
subshapes = pointAnnotations;
- } else if ([shape isKindOfClass:[MGLMultiPolyline class]]) {
- subshapes = [(MGLMultiPolyline *)shape polylines];
- } else if ([shape isKindOfClass:[MGLMultiPolygon class]]) {
- subshapes = [(MGLMultiPolygon *)shape polygons];
} else if ([shape isKindOfClass:[MGLShapeCollection class]]) {
subshapes = MBXFlattenedShapes([(MGLShapeCollection *)shape shapes]);
}
-
+
if (subshapes) {
[flattenedShapes addObjectsFromArray:subshapes];
} else {
@@ -63,11 +62,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
/// Style URL inherited from an existing document at the time this document
/// was created.
NSURL *_inheritedStyleURL;
-
+
NSPoint _mouseLocationForMapViewContextMenu;
NSUInteger _droppedPinCounter;
NSNumberFormatter *_spellOutNumberFormatter;
-
+
BOOL _isLocalizingLabels;
BOOL _showsToolTipsOnDroppedPins;
BOOL _randomizesCursorsOnDroppedPins;
@@ -95,19 +94,19 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (void)windowControllerDidLoadNib:(NSWindowController *)controller {
[super windowControllerDidLoadNib:controller];
-
+
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:nil];
-
+
_spellOutNumberFormatter = [[NSNumberFormatter alloc] init];
-
+
NSPressGestureRecognizer *pressGestureRecognizer = [[NSPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePressGesture:)];
[self.mapView addGestureRecognizer:pressGestureRecognizer];
-
+
[self.splitView setPosition:0 ofDividerAtIndex:0];
-
+
[self applyPendingState];
}
@@ -217,11 +216,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (IBAction)zoomIn:(id)sender {
- [self.mapView setZoomLevel:self.mapView.zoomLevel + 1 animated:YES];
+ [self.mapView setZoomLevel:round(self.mapView.zoomLevel) + 1 animated:YES];
}
- (IBAction)zoomOut:(id)sender {
- [self.mapView setZoomLevel:self.mapView.zoomLevel - 1 animated:YES];
+ [self.mapView setZoomLevel:round(self.mapView.zoomLevel) - 1 animated:YES];
}
- (IBAction)snapToNorth:(id)sender {
@@ -263,7 +262,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager registerUndoWithTarget:self handler:^(MapDocument * _Nonnull target) {
[target toggleStyleLayersAtArrangedObjectIndexes:indices];
}];
-
+
if (!self.undoManager.undoing) {
NSString *actionName;
if (indices.count == 1) {
@@ -276,11 +275,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager setActionIsDiscardable:YES];
[self.undoManager setActionName:actionName];
}
-
+
for (MGLStyleLayer *layer in layers) {
layer.visible = !isVisible;
}
-
+
NSIndexSet *columnIndices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, 2)];
[self.styleLayersTableView reloadDataForRowIndexes:indices columnIndexes:columnIndices];
}
@@ -298,7 +297,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self deleteStyleLayersAtArrangedObjectIndexes:indices];
}];
-
+
if (!self.undoManager.undoing) {
NSString *actionName;
if (indices.count == 1) {
@@ -309,7 +308,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
[self.undoManager setActionName:actionName];
}
-
+
[self.styleLayersArrayController insertObjects:layers atArrangedObjectIndexes:indices];
}
@@ -318,7 +317,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertStyleLayers:layers atArrangedObjectIndexes:indices];
}];
-
+
if (!self.undoManager.undoing) {
NSString *actionName;
if (indices.count == 1) {
@@ -329,7 +328,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
[self.undoManager setActionName:actionName];
}
-
+
[self.styleLayersArrayController removeObjectsAtArrangedObjectIndexes:indices];
}
@@ -346,17 +345,17 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (![layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
continue;
}
-
+
MGLVectorSource *source = (MGLVectorSource *)[style sourceWithIdentifier:layer.sourceIdentifier];
if (![source isKindOfClass:[MGLVectorSource class]] || !source.mapboxStreets) {
continue;
}
-
+
NSDictionary *localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier];
if (!localizedKeysByKey) {
localizedKeysByKey = localizedKeysByKeyBySourceIdentifier[layer.sourceIdentifier] = [source localizedKeysByKeyForPreferredLanguage:preferredLanguage];
}
-
+
NSString *(^stringByLocalizingString)(NSString *) = ^ NSString * (NSString *string) {
NSMutableString *localizedString = string.mutableCopy;
[localizedKeysByKey enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull localizedKey, BOOL * _Nonnull stop) {
@@ -369,12 +368,13 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}];
return localizedString;
};
-
+
if ([layer.text isKindOfClass:[MGLStyleConstantValue class]]) {
NSString *textField = [(MGLStyleConstantValue<NSString *> *)layer.text rawValue];
layer.text = [MGLStyleValue<NSString *> valueWithRawValue:stringByLocalizingString(textField)];
- } else if ([layer.text isKindOfClass:[MGLStyleFunction class]]) {
- MGLStyleFunction *function = (MGLStyleFunction<NSString *> *)layer.text;
+ }
+ else if ([layer.text isKindOfClass:[MGLCameraStyleFunction class]]) {
+ MGLCameraStyleFunction *function = (MGLCameraStyleFunction<NSString *> *)layer.text;
NSMutableDictionary *stops = function.stops.mutableCopy;
[stops enumerateKeysAndObjectsUsingBlock:^(NSNumber *zoomLevel, MGLStyleConstantValue<NSString *> *stop, BOOL *done) {
NSString *textField = stop.rawValue;
@@ -391,7 +391,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
self.mapView.styleURL = _inheritedStyleURL;
_inheritedStyleURL = nil;
}
-
+
AppDelegate *appDelegate = (AppDelegate *)NSApp.delegate;
if (appDelegate.pendingStyleURL) {
self.mapView.styleURL = appDelegate.pendingStyleURL;
@@ -420,7 +420,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
self.mapView.zoomLevel = MIN(appDelegate.pendingMaximumZoomLevel, self.mapView.zoomLevel);
appDelegate.pendingMaximumZoomLevel = -1;
}
-
+
// Temporarily set the display name to the default center coordinate instead
// of “Untitled” until the binding kicks in.
NSValue *coordinateValue = [NSValue valueWithMGLCoordinate:self.mapView.centerCoordinate];
@@ -475,7 +475,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)dropManyPins:(id)sender {
[self removeAllAnnotations:sender];
-
+
NSRect bounds = self.mapView.bounds;
NSMutableArray *annotations = [NSMutableArray array];
for (CGFloat x = NSMinX(bounds); x < NSMaxX(bounds); x += arc4random_uniform(50)) {
@@ -483,7 +483,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[annotations addObject:[self pinAtPoint:NSMakePoint(x, y)]];
}
}
-
+
[NSTimer scheduledTimerWithTimeInterval:1.0/60.0
target:self
selector:@selector(dropOneOfManyPins:)
@@ -518,7 +518,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (IBAction)startWorldTour:(id)sender {
_isTouringWorld = YES;
-
+
[self removeAllAnnotations:sender];
NSUInteger numberOfAnnotations = sizeof(WorldTourDestinations) / sizeof(WorldTourDestinations[0]);
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:numberOfAnnotations];
@@ -537,7 +537,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
_isTouringWorld = NO;
return;
}
-
+
[annotations removeObjectAtIndex:0];
MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:nextAnnotation.coordinate
fromDistance:0
@@ -612,11 +612,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self removeCustomStyleLayer:sender];
}];
-
+
if (!self.undoManager.isUndoing) {
[self.undoManager setActionName:@"Add Lime Green Layer"];
}
-
+
LimeGreenStyleLayer *layer = [[LimeGreenStyleLayer alloc] initWithIdentifier:@"mbx-custom"];
MGLStyleLayer *houseNumberLayer = [self.mapView.style layerWithIdentifier:@"housenum-label"];
if (houseNumberLayer) {
@@ -630,11 +630,11 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertCustomStyleLayer:sender];
}];
-
+
if (!self.undoManager.isUndoing) {
[self.undoManager setActionName:@"Delete Lime Green Layer"];
}
-
+
MGLStyleLayer *layer = [self.mapView.style layerWithIdentifier:@"mbx-custom"];
[self.mapView.style removeLayer:layer];
}
@@ -698,7 +698,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if ([namePrompt runModal] != NSAlertFirstButtonReturn) {
return;
}
-
+
id <MGLOfflineRegion> region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:self.mapView.styleURL bounds:self.mapView.visibleCoordinateBounds fromZoomLevel:self.mapView.zoomLevel toZoomLevel:self.mapView.maximumZoomLevel];
NSData *context = [[NSValueTransformer valueTransformerForName:@"OfflinePackNameValueTransformer"] reverseTransformedValue:nameTextField.stringValue];
[[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) {
@@ -728,38 +728,38 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
self.mapView.style.transitionDelay = 1;
MGLFillStyleLayer *fillStyleLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"];
-
- MGLStyleValue *colorFunction = [MGLStyleValue<NSColor *> valueWithStops:@{
+
+ MGLStyleValue *colorFunction = [MGLStyleValue<NSColor *> valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@0.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor redColor]],
@10.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor blackColor]],
- }];
+ } options:nil];
fillStyleLayer.fillColor = colorFunction;
-
+
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"ams" URL:geoJSONURL options:nil];
[self.mapView.style addSource:source];
-
+
MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"test" source:source];
fillLayer.fillColor = [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor greenColor]];
fillLayer.predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"type", @"park"];
[self.mapView.style addLayer:fillLayer];
-
+
NSImage *image = [NSImage imageNamed:NSImageNameIChatTheaterTemplate];
[self.mapView.style setImage:image forName:NSImageNameIChatTheaterTemplate];
-
+
MGLSource *streetsSource = [self.mapView.style sourceWithIdentifier:@"composite"];
MGLSymbolStyleLayer *theaterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"theaters" source:streetsSource];
theaterLayer.sourceLayerIdentifier = @"poi_label";
theaterLayer.predicate = [NSPredicate predicateWithFormat:@"maki == 'theatre'"];
theaterLayer.iconImageName = [MGLStyleValue valueWithRawValue:NSImageNameIChatTheaterTemplate];
theaterLayer.iconScale = [MGLStyleValue valueWithRawValue:@2];
- theaterLayer.iconColor = [MGLStyleValue valueWithStops:@{
+ theaterLayer.iconColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@16.0: [MGLStyleValue valueWithRawValue:[NSColor redColor]],
@18.0: [MGLStyleValue valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue valueWithRawValue:[NSColor blackColor]],
- }];
+ } options:nil];
[self.mapView.style addLayer:theaterLayer];
}
@@ -781,7 +781,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
title = [feature attributeForKey:@"name_en"] ?: [feature attributeForKey:@"name"];
}
}
-
+
DroppedPinAnnotation *annotation = [[DroppedPinAnnotation alloc] init];
annotation.coordinate = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
annotation.title = title ?: @"Dropped Pin";
@@ -993,7 +993,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (![MGLAccountManager accessToken]) {
return NSNotFound;
}
-
+
NSArray *styleURLs = @[
[MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion],
[MGLStyle outdoorsStyleURLWithVersion:MGLStyleDefaultVersion],
@@ -1009,7 +1009,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (!self.mapView) {
return NO;
}
-
+
SEL action = toolbarItem.action;
if (action == @selector(showShareMenu:)) {
[(NSButton *)toolbarItem.view sendActionOn:NSLeftMouseDownMask];
@@ -1047,14 +1047,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
NSImage *browserIcon = [[NSWorkspace sharedWorkspace] iconForFile:browserURL.path];
NSString *browserName = [[NSFileManager defaultManager] displayNameAtPath:browserURL.path];
NSString *browserServiceName = [NSString stringWithFormat:@"Open in %@", browserName];
-
+
NSSharingService *browserService = [[NSSharingService alloc] initWithTitle:browserServiceName
image:browserIcon
alternateImage:nil
handler:^{
[[NSWorkspace sharedWorkspace] openURL:self.shareURL];
}];
-
+
NSMutableArray *sharingServices = [proposedServices mutableCopy];
[sharingServices insertObject:browserService atIndex:0];
return sharingServices;
@@ -1123,14 +1123,14 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
- (void)mapView:(MGLMapView *)mapView didSelectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
- DroppedPinAnnotation *droppedPin = annotation;
+ DroppedPinAnnotation *droppedPin = (DroppedPinAnnotation *)annotation;
[droppedPin resume];
}
}
- (void)mapView:(MGLMapView *)mapView didDeselectAnnotation:(id <MGLAnnotation>)annotation {
if ([annotation isKindOfClass:[DroppedPinAnnotation class]]) {
- DroppedPinAnnotation *droppedPin = annotation;
+ DroppedPinAnnotation *droppedPin = (DroppedPinAnnotation *)annotation;
[droppedPin pause];
}
}
diff --git a/platform/macos/app/OfflinePackNameValueTransformer.m b/platform/macos/app/OfflinePackNameValueTransformer.m
index 2825e48ed3..d1b3c20ac1 100644
--- a/platform/macos/app/OfflinePackNameValueTransformer.m
+++ b/platform/macos/app/OfflinePackNameValueTransformer.m
@@ -14,7 +14,7 @@ static NSString * const MBXOfflinePackContextNameKey = @"Name";
- (NSString *)transformedValue:(NSData *)context {
NSAssert([context isKindOfClass:[NSData class]], @"Context should be NSData.");
-
+
NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:context];
NSAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline pack isn’t a dictionary.");
NSString *name = userInfo[MBXOfflinePackContextNameKey];
@@ -24,7 +24,7 @@ static NSString * const MBXOfflinePackContextNameKey = @"Name";
- (NSData *)reverseTransformedValue:(NSString *)name {
NSAssert([name isKindOfClass:[NSString class]], @"Name should be a string.");
-
+
return [NSKeyedArchiver archivedDataWithRootObject:@{
MBXOfflinePackContextNameKey: name,
}];
diff --git a/platform/macos/app/StyleLayerIconTransformer.m b/platform/macos/app/StyleLayerIconTransformer.m
index 93f59abb3e..ff2b964b87 100644
--- a/platform/macos/app/StyleLayerIconTransformer.m
+++ b/platform/macos/app/StyleLayerIconTransformer.m
@@ -31,7 +31,7 @@
if ([layer isKindOfClass:[MGLSymbolStyleLayer class]]) {
return [NSImage imageNamed:@"symbol"];
}
-
+
return nil;
}
diff --git a/platform/macos/app/TimeIntervalTransformer.m b/platform/macos/app/TimeIntervalTransformer.m
index 39177dc5bc..2c9cb6fc74 100644
--- a/platform/macos/app/TimeIntervalTransformer.m
+++ b/platform/macos/app/TimeIntervalTransformer.m
@@ -18,7 +18,7 @@ NSString *NumberAndUnitString(NSInteger quantity, NSString *singular, NSString *
if (![value isKindOfClass:[NSValue class]]) {
return nil;
}
-
+
NSTimeInterval timeInterval = [value doubleValue];
NSInteger seconds = floor(timeInterval);
NSInteger minutes = floor(seconds / 60);
@@ -29,7 +29,7 @@ NSString *NumberAndUnitString(NSInteger quantity, NSString *singular, NSString *
hours -= days * 24;
NSInteger weeks = floor(days) / 7;
days -= weeks * 7;
-
+
NSMutableArray *components = [NSMutableArray array];
if (seconds || timeInterval < 60) {
[components addObject:NumberAndUnitString(seconds, @"second", @"seconds")];
@@ -46,7 +46,7 @@ NSString *NumberAndUnitString(NSInteger quantity, NSString *singular, NSString *
if (weeks) {
[components insertObject:NumberAndUnitString(weeks, @"week", @"weeks") atIndex:0];
}
-
+
return [components componentsJoinedByString:@", "];
}
diff --git a/platform/macos/app/de.lproj/Localizable.strings b/platform/macos/app/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/de.lproj/Localizable.strings
diff --git a/platform/macos/app/es.lproj/Localizable.strings b/platform/macos/app/es.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/es.lproj/Localizable.strings
diff --git a/platform/macos/app/fr.lproj/Localizable.strings b/platform/macos/app/fr.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/fr.lproj/Localizable.strings
diff --git a/platform/macos/app/ja.lproj/Localizable.strings b/platform/macos/app/ja.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/ja.lproj/Localizable.strings
diff --git a/platform/macos/app/lt.lproj/Localizable.strings b/platform/macos/app/lt.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/lt.lproj/Localizable.strings
diff --git a/platform/macos/app/pl.lproj/Localizable.strings b/platform/macos/app/pl.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/pl.lproj/Localizable.strings
diff --git a/platform/macos/app/pt-BR.lproj/Localizable.strings b/platform/macos/app/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/pt-BR.lproj/Localizable.strings
diff --git a/platform/macos/app/sv.lproj/Localizable.strings b/platform/macos/app/sv.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/sv.lproj/Localizable.strings
diff --git a/platform/macos/app/uk.lproj/Localizable.strings b/platform/macos/app/uk.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/uk.lproj/Localizable.strings
diff --git a/platform/macos/app/vi.lproj/Localizable.strings b/platform/macos/app/vi.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/vi.lproj/Localizable.strings
diff --git a/platform/macos/app/zh-Hans.lproj/Localizable.strings b/platform/macos/app/zh-Hans.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/zh-Hans.lproj/Localizable.strings
diff --git a/platform/macos/app/zh-Hant.lproj/Localizable.strings b/platform/macos/app/zh-Hant.lproj/Localizable.strings
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/platform/macos/app/zh-Hant.lproj/Localizable.strings
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index d7a9c894b8..309d8e82f3 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -1,9 +1,9 @@
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10)
-mason_use(glfw VERSION 3.2.1)
+mason_use(glfw VERSION 2017-02-09-77a8f10)
mason_use(boost_libprogram_options VERSION 1.62.0)
-mason_use(gtest VERSION 1.7.0${MASON_CXXABI_SUFFIX})
-mason_use(benchmark VERSION 1.0.0)
+mason_use(gtest VERSION 1.8.0)
+mason_use(benchmark VERSION 1.0.0-1)
mason_use(icu VERSION 58.1)
include(cmake/loop-darwin.cmake)
@@ -40,7 +40,9 @@ macro(mbgl_platform_core)
PRIVATE platform/default/utf.cpp
# Image handling
+ PRIVATE platform/darwin/mbgl/util/image+MGLAdditions.hpp
PRIVATE platform/darwin/src/image.mm
+ PRIVATE platform/default/png_writer.cpp
# Headless view
PRIVATE platform/default/mbgl/gl/headless_backend.cpp
@@ -52,6 +54,8 @@ macro(mbgl_platform_core)
PRIVATE platform/default/mbgl/gl/offscreen_view.hpp
# Thread pool
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
)
diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
index cf25ae09c4..78a3063b06 100644
--- a/platform/macos/docs/guides/For Style Authors.md
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -26,6 +26,8 @@ style is present. Standard user interface elements such as toolbars, sidebars,
and sheets often overlap the map view with a translucent, blurred background, so
make sure the contents of these elements remain legible with the map view
underneath.
+If you intend your style to be used in the dark, consider the impact that Night
+Shift may have on your style’s colors.
### Typography and graphics
@@ -115,7 +117,7 @@ In style JSON | In the SDK
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
-`image` and `video` sources are not supported.
+`canvas`, `image`, and `video` sources are not supported.
### Tile sources
@@ -263,9 +265,10 @@ Array (`-offset`, `-translate`) | `NSValue` containing `CGVector` | `NSValue` co
Array (`-padding`) | `NSValue.edgeInsetsValue` | `NSValue.edgeInsetsValue`
For padding attributes, note that the arguments to
-`NSEdgeInsetsMake()` in Objective-C and
-`EdgeInsets(top:left:bottom:right:)` in Swift are specified in counterclockwise
-order, in contrast to the clockwise order defined by the style specification.
+`NSEdgeInsetsMake()` in Objective-C and `EdgeInsets(top:left:bottom:right:)` in
+Swift
+are specified in counterclockwise order, in contrast to the clockwise order
+defined by the style specification.
Additionally, on macOS, a screen coordinate of (0, 0) is located at the
lower-left corner of the screen. Therefore, a positive `CGVector.dy` means an
diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md
index 6d45a68c34..33386340c6 100644
--- a/platform/macos/docs/pod-README.md
+++ b/platform/macos/docs/pod-README.md
@@ -2,7 +2,7 @@
Put interactive, scalable world maps into your native Cocoa application with the open-source Mapbox macOS SDK.
-* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
+* Mapbox-curated [map styles](https://www.mapbox.com/maps/) and [OpenStreetMap-based](https://www.mapbox.com/vector-tiles/mapbox-streets-v7/) [vector tiles](https://www.mapbox.com/vector-tiles/) make it easy to get started.
* Customize every aspect of the map’s appearance in code or visually using [Mapbox Studio](https://www.mapbox.com/mapbox-studio/).
* High-performance OpenGL rendering and multitouch gestures keep your users happy.
* A well-designed, fully documented API helps you stay productive.
@@ -12,10 +12,10 @@ Put interactive, scalable world maps into your native Cocoa application with the
The Mapbox macOS SDK 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/).
-Mapbox macOS SDK releases are [available on GitHub](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “macos-”. You can also integrate the Mapbox macOS SDK into your application using CocoaPods.
-
## Installation
+1. Download the [latest Mapbox macOS SDK release](https://github.com/mapbox/mapbox-gl-native/releases/) from GitHub – look for a release that begins with “macos-”. (Alternatively, you can integrate the Mapbox macOS SDK into your application [using CocoaPods](https://cocoapods.org/pods/Mapbox-macOS-SDK). If you do use CocoaPods, skip the next step.)
+
1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish.
1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom macOS Application Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/).
diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml
index 8aa93a41f7..65a3451043 100644
--- a/platform/macos/jazzy.yml
+++ b/platform/macos/jazzy.yml
@@ -105,3 +105,4 @@ custom_categories:
- MGLClockDirectionFormatter
- MGLCompassDirectionFormatter
- MGLCoordinateFormatter
+ - MGLDistanceFormatter
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 6b8a038a68..4315698741 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
+ 1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
30E5781B1DAA857E0050F07E /* NSImage+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */; };
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */; };
3508EC651D749D39009B0EE4 /* NSExpression+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */; };
@@ -42,6 +43,9 @@
35C5D8481D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D8441D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm */; };
35C5D8491D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35C5D8451D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h */; };
35C5D84A1D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35C5D8461D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm */; };
+ 35C6DF841E214C0400ACA483 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 35C6DF821E214C0400ACA483 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 35C6DF851E214C0400ACA483 /* MGLDistanceFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C6DF831E214C0400ACA483 /* MGLDistanceFormatter.m */; };
+ 35C6DF871E214C1800ACA483 /* MGLDistanceFormatterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */; };
35D65C5A1D65AD5500722C23 /* NSDate+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */; };
35D65C5B1D65AD5500722C23 /* NSDate+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */; };
4049C2A51DB6CE7F00B3F799 /* MGLPointCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -61,8 +65,12 @@
5548BE781D09E718005DDE81 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; };
556660C61E1BEA0100E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C51E1BEA0100E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D61E1D07E400E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D51E1D07E400E2C41B /* MGLVersionNumber.m */; };
+ 558DE7A61E56161C00C7916D /* MGLFoundation_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */; };
+ 558DE7A71E56161C00C7916D /* MGLFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 558DE7A51E56161C00C7916D /* MGLFoundation.mm */; };
558F18221D0B13B100123F46 /* libmbgl-loop.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 558F18211D0B13B000123F46 /* libmbgl-loop.a */; };
55D9B4B11D005D3900C1CCE2 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 55D9B4B01D005D3900C1CCE2 /* libz.tbd */; };
+ 55E2AD111E5B0A6900E8C587 /* MGLOfflineStorageTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */; };
+ 96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; };
8877024C1E37977D0097E255 /* MGLComputedShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 88B079B01E3794F300834FAB /* MGLComputedShapeSource.mm */; };
88B079AC1E37941300834FAB /* MGLAbstractShapeSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 88B079AA1E3793E000834FAB /* MGLAbstractShapeSource.mm */; };
88B079AD1E37942700834FAB /* MGLAbstractShapeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 88B079A91E3793E000834FAB /* MGLAbstractShapeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -213,7 +221,6 @@
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */; };
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */; };
DAE6C3D41CC34C9900DB3429 /* MGLOfflineRegionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */; };
- DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */; };
DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */; };
DAE7DEC41E24549F007505A6 /* MGLNSStringAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */; };
DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */; };
@@ -260,6 +267,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
30E578141DAA7D920050F07E /* NSImage+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSImage+MGLAdditions.h"; path = "src/NSImage+MGLAdditions.h"; sourceTree = SOURCE_ROOT; };
3508EC621D749D39009B0EE4 /* NSExpression+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSExpression+MGLAdditions.h"; sourceTree = "<group>"; };
3508EC631D749D39009B0EE4 /* NSExpression+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSExpression+MGLAdditions.mm"; sourceTree = "<group>"; };
@@ -296,6 +304,9 @@
35C5D8451D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSCompoundPredicate+MGLAdditions.h"; sourceTree = "<group>"; };
35C5D8461D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSCompoundPredicate+MGLAdditions.mm"; sourceTree = "<group>"; };
35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLPredicateTests.mm; path = ../../darwin/test/MGLPredicateTests.mm; sourceTree = "<group>"; };
+ 35C6DF821E214C0400ACA483 /* MGLDistanceFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLDistanceFormatter.h; sourceTree = "<group>"; };
+ 35C6DF831E214C0400ACA483 /* MGLDistanceFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLDistanceFormatter.m; sourceTree = "<group>"; };
+ 35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLDistanceFormatterTests.m; path = ../../darwin/test/MGLDistanceFormatterTests.m; sourceTree = "<group>"; };
35D65C581D65AD5500722C23 /* NSDate+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+MGLAdditions.h"; sourceTree = "<group>"; };
35D65C591D65AD5500722C23 /* NSDate+MGLAdditions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSDate+MGLAdditions.mm"; sourceTree = "<group>"; };
4049C2A11DB6CE7800B3F799 /* MGLPointCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPointCollection.h; sourceTree = "<group>"; };
@@ -318,17 +329,35 @@
5548BE7B1D0ACBBD005DDE81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop-darwin.a"; path = "cmake/Debug/libmbgl-loop-darwin.a"; sourceTree = "<group>"; };
556660C51E1BEA0100E2C41B /* MGLFoundation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLFoundation.h; sourceTree = "<group>"; };
556660D51E1D07E400E2C41B /* MGLVersionNumber.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLVersionNumber.m; path = ../../darwin/test/MGLVersionNumber.m; sourceTree = "<group>"; };
+ 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = "<group>"; };
+ 558DE7A51E56161C00C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = "<group>"; };
558F18211D0B13B000123F46 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/osx/Debug/libmbgl-loop.a"; sourceTree = "<group>"; };
55D9B4B01D005D3900C1CCE2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+ 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLOfflineStorageTests.mm; path = ../../darwin/test/MGLOfflineStorageTests.mm; sourceTree = "<group>"; };
55FE0E8D1D100A0900FD240B /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/macos/config.xcconfig; sourceTree = "<group>"; };
+ 966091701E5BBFF700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 966091711E5BBFF900A9A03B /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 966091721E5BBFFA00A9A03B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 966091731E5BBFFA00A9A03B /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
88B079A81E3793E000834FAB /* MGLAbstractShapeSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAbstractShapeSource_Private.h; sourceTree = "<group>"; };
+ 96E027321E57C9A7004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E027341E57C9A9004B8E66 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
88B079A91E3793E000834FAB /* MGLAbstractShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAbstractShapeSource.h; sourceTree = "<group>"; };
+ 96E027351E57C9AB004B8E66 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ 96E027361E57C9AC004B8E66 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
88B079AA1E3793E000834FAB /* MGLAbstractShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAbstractShapeSource.mm; sourceTree = "<group>"; };
+ 96E027371E57C9B5004B8E66 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E027381E57C9B7004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
88B079AF1E3794F300834FAB /* MGLComputedShapeSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLComputedShapeSource.h; sourceTree = "<group>"; };
+ 96E027391E57C9B9004B8E66 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 96E0273A1E57C9BB004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
88B079B01E3794F300834FAB /* MGLComputedShapeSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLComputedShapeSource.mm; sourceTree = "<group>"; };
+ 96E0273B1E57C9BC004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
DA00FC881D5EEAC3009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = "<group>"; };
DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = "<group>"; };
DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLFeatureTests.mm; path = ../../darwin/test/MGLFeatureTests.mm; sourceTree = "<group>"; };
+ DA1AC01E1E5B8826006DF1D6 /* lt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA1AC01F1E5B8904006DF1D6 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA2207BA1DC076930002F84D /* test-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Bridging-Header.h"; sourceTree = "<group>"; };
DA2207BB1DC076940002F84D /* MGLStyleValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MGLStyleValueTests.swift; sourceTree = "<group>"; };
DA2784FD1DF03060001D5B8D /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = ../../darwin/test/Media.xcassets; sourceTree = "<group>"; };
@@ -349,10 +378,17 @@
DA551B801DB496AC0009AFAF /* MGLTileSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTileSource_Private.h; sourceTree = "<group>"; };
DA551B811DB496AC0009AFAF /* MGLTileSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLTileSource.mm; sourceTree = "<group>"; };
DA5589761D320C41006B7F64 /* wms.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = wms.json; sourceTree = "<group>"; };
+ DA6023EF1E4CE8E500DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DA6023F01E4CE8FF00DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
DA6408D51DA4E5DA00908C90 /* MGLVectorStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorStyleLayer.h; sourceTree = "<group>"; };
DA6408D61DA4E5DA00908C90 /* MGLVectorStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLVectorStyleLayer.m; sourceTree = "<group>"; };
DA7262051DEEDD460043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; };
DA7262061DEEDD460043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; };
+ DA737ADE1E5914AD00AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DA737ADF1E5914D300AD2CDE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737AE31E5915A500AD2CDE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = pl; path = pl.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DA737AE41E5915B000AD2CDE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DA737AEC1E59180E00AD2CDE /* uk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLVectorSource_Private.h; sourceTree = "<group>"; };
DA7DC9821DED647F0027472F /* MGLRasterSource_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRasterSource_Private.h; sourceTree = "<group>"; };
DA839E921CC2E3400062CAFB /* Mapbox GL.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Mapbox GL.app"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -398,7 +434,19 @@
DA8F25B51D51D2240010E6B5 /* MGLStyleLayerTests.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; name = MGLStyleLayerTests.mm.ejs; path = ../test/MGLStyleLayerTests.mm.ejs; sourceTree = "<group>"; };
DA8F25B61D51D2240010E6B5 /* MGLStyleLayer.h.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.h.ejs; sourceTree = "<group>"; };
DA8F25B71D51D2240010E6B5 /* MGLStyleLayer.mm.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = MGLStyleLayer.mm.ejs; sourceTree = "<group>"; };
+ DA9C01301E4C7B9300C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-BR"; path = "pt-BR.lproj/Foundation.stringsdict"; sourceTree = "<group>"; };
+ DA9C01311E4C7B9F00C4742A /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = "<group>"; };
DAA1BB491E2D425C00ABB750 /* libmbgl-loop.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-loop.a"; path = "../../build/macos/Debug/libmbgl-loop.a"; sourceTree = "<group>"; };
+ DAA32CA61E4C4849006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CA71E4C486D006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CA81E4C48B9006F8D24 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DAA32CAE1E4C4B03006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
+ DAA32CAF1E4C4B0D006F8D24 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CB21E4C4CB7006F8D24 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CB31E4C4CC3006F8D24 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CBA1E4C4F10006F8D24 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
+ DAA32CC01E4C4F89006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Foundation.strings; sourceTree = "<group>"; };
+ DAA32CC11E4C4F93006F8D24 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = "<group>"; };
DAA48EFB1D6A4731006A7E36 /* StyleLayerIconTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleLayerIconTransformer.h; sourceTree = "<group>"; };
DAA48EFC1D6A4731006A7E36 /* StyleLayerIconTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StyleLayerIconTransformer.m; sourceTree = "<group>"; };
DAB2CCE31DF632ED001B2FE1 /* LimeGreenStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LimeGreenStyleLayer.h; sourceTree = "<group>"; };
@@ -489,7 +537,6 @@
DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = "<group>"; };
DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = "<group>"; };
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
- DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineStorageTests.m; path = ../../darwin/test/MGLOfflineStorageTests.m; sourceTree = "<group>"; };
DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLNSStringAdditionsTests.m; path = ../../darwin/test/MGLNSStringAdditionsTests.m; sourceTree = "<group>"; };
DAED385D1D62CED700D7640F /* NSURL+MGLAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+MGLAdditions.h"; sourceTree = "<group>"; };
@@ -500,6 +547,8 @@
DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo_Private.h; sourceTree = "<group>"; };
DAF0D81A1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MGLVectorSource+MBXAdditions.h"; sourceTree = "<group>"; };
DAF0D81B1DFF567C00B28378 /* MGLVectorSource+MBXAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MGLVectorSource+MBXAdditions.m"; sourceTree = "<group>"; };
+ DAFBD0D51E3FA969000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
+ DAFBD0D61E3FA983000CD6BF /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Foundation.strings"; sourceTree = "<group>"; };
DD0902AF1DB1AC6400C5BDCE /* MGLNetworkConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfiguration.m; sourceTree = "<group>"; };
DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLNetworkConfiguration.h; sourceTree = "<group>"; };
DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLExpressionTests.mm; path = ../../darwin/test/MGLExpressionTests.mm; sourceTree = "<group>"; };
@@ -606,6 +655,7 @@
3527429B1D4C259500A1ECE6 /* Styling */ = {
isa = PBXGroup;
children = (
+ 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */,
352742791D4C235C00A1ECE6 /* Categories */,
35136D471D42295400C20EFD /* Layers */,
3527427E1D4C242B00A1ECE6 /* Sources */,
@@ -668,6 +718,7 @@
DA5589761D320C41006B7F64 /* wms.json */,
DAE6C2E11CC304F900DB3429 /* Credits.rtf */,
DA839EA61CC2E3400062CAFB /* Info.plist */,
+ 96E027331E57C9A7004B8E66 /* Localizable.strings */,
DA839E981CC2E3400062CAFB /* Supporting Files */,
);
name = "Demo App";
@@ -772,6 +823,8 @@
DA35A2AC1CCA091800E826B2 /* MGLCompassDirectionFormatter.m */,
DA35A2A31CC9EB1A00E826B2 /* MGLCoordinateFormatter.h */,
DA35A2A51CC9EB2700E826B2 /* MGLCoordinateFormatter.m */,
+ 35C6DF821E214C0400ACA483 /* MGLDistanceFormatter.h */,
+ 35C6DF831E214C0400ACA483 /* MGLDistanceFormatter.m */,
);
name = Formatters;
sourceTree = "<group>";
@@ -906,12 +959,13 @@
DA35A2A71CC9F41600E826B2 /* MGLCoordinateFormatterTests.m */,
DA2987591E1A4290002299F5 /* MGLDocumentationExampleTests.swift */,
DD58A4C71D822C6200E1F038 /* MGLExpressionTests.mm */,
+ 35C6DF861E214C1800ACA483 /* MGLDistanceFormatterTests.m */,
DA0CD58D1CF56F5800A5F5A5 /* MGLFeatureTests.mm */,
DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */,
DAE7DEC31E24549F007505A6 /* MGLNSStringAdditionsTests.m */,
DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */,
DAE6C3CA1CC34BD800DB3429 /* MGLOfflineRegionTests.m */,
- DAE6C3CB1CC34BD800DB3429 /* MGLOfflineStorageTests.m */,
+ 55E2AD101E5B0A6900E8C587 /* MGLOfflineStorageTests.mm */,
35C5D84B1D6DD75B00E95907 /* MGLPredicateTests.mm */,
DAE6C3CC1CC34BD800DB3429 /* MGLStyleTests.mm */,
556660D51E1D07E400E2C41B /* MGLVersionNumber.m */,
@@ -938,6 +992,8 @@
DAF0D8151DFE6B1800B28378 /* MGLAttributionInfo_Private.h */,
DA00FC891D5EEAC3009AABC8 /* MGLAttributionInfo.mm */,
556660C51E1BEA0100E2C41B /* MGLFoundation.h */,
+ 558DE7A41E56161C00C7916D /* MGLFoundation_Private.h */,
+ 558DE7A51E56161C00C7916D /* MGLFoundation.mm */,
DAE6C34D1CC31E0400DB3429 /* MGLMapCamera.h */,
DAE6C36E1CC31E2A00DB3429 /* MGLMapCamera.mm */,
DD0902B01DB1AC6400C5BDCE /* MGLNetworkConfiguration.h */,
@@ -997,6 +1053,7 @@
3508EC641D749D39009B0EE4 /* NSExpression+MGLAdditions.h in Headers */,
DAE6C38D1CC31E2A00DB3429 /* MGLOfflineRegion_Private.h in Headers */,
DA7DC9831DED647F0027472F /* MGLRasterSource_Private.h in Headers */,
+ 1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */,
408AA8651DAEEE3400022900 /* MGLPolygon+MGLAdditions.h in Headers */,
DA8F259C1D51CB000010E6B5 /* MGLStyleValue_Private.h in Headers */,
DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */,
@@ -1047,6 +1104,7 @@
DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */,
DAE6C39A1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.h in Headers */,
DA8F258B1D51CA540010E6B5 /* MGLLineStyleLayer.h in Headers */,
+ 35C6DF841E214C0400ACA483 /* MGLDistanceFormatter.h in Headers */,
DA8F25B21D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.h in Headers */,
359819591E02F611008FC139 /* NSCoder+MGLAdditions.h in Headers */,
DAE6C38E1CC31E2A00DB3429 /* MGLOfflineStorage_Private.h in Headers */,
@@ -1057,6 +1115,7 @@
DA35A2CF1CCAAED300E826B2 /* NSValue+MGLAdditions.h in Headers */,
DAE6C3A61CC31E9400DB3429 /* MGLMapViewDelegate.h in Headers */,
DAE6C38B1CC31E2A00DB3429 /* MGLOfflinePack_Private.h in Headers */,
+ 558DE7A61E56161C00C7916D /* MGLFoundation_Private.h in Headers */,
88B079B21E37957000834FAB /* MGLComputedShapeSource.h in Headers */,
DACC22141CF3D3E200D220D9 /* MGLFeature.h in Headers */,
3538AA231D542685008EC33D /* MGLStyleLayer.h in Headers */,
@@ -1195,6 +1254,17 @@
en,
Base,
"zh-Hans",
+ "zh-Hant",
+ de,
+ fr,
+ ja,
+ sv,
+ vi,
+ "pt-BR",
+ es,
+ pl,
+ uk,
+ lt,
);
mainGroup = DA839E891CC2E3400062CAFB;
productRefGroup = DA839E931CC2E3400062CAFB /* Products */;
@@ -1217,6 +1287,7 @@
DA839EA21CC2E3400062CAFB /* Assets.xcassets in Resources */,
DA839EA01CC2E3400062CAFB /* MapDocument.xib in Resources */,
353BAEF81D6463B8009A8DA9 /* amsterdam.geojson in Resources */,
+ 96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */,
DA839EA51CC2E3400062CAFB /* MainMenu.xib in Resources */,
DA5589771D320C41006B7F64 /* wms.json in Resources */,
DAE6C2E21CC304F900DB3429 /* Credits.rtf in Resources */,
@@ -1288,6 +1359,7 @@
35602BFB1D3EA99F0050646F /* MGLFillStyleLayer.mm in Sources */,
DAE6C3931CC31E2A00DB3429 /* MGLShape.mm in Sources */,
352742861D4C244700A1ECE6 /* MGLRasterSource.mm in Sources */,
+ 558DE7A71E56161C00C7916D /* MGLFoundation.mm in Sources */,
DAE6C39D1CC31E2A00DB3429 /* NSString+MGLAdditions.m in Sources */,
3598195A1E02F611008FC139 /* NSCoder+MGLAdditions.mm in Sources */,
DAE6C3941CC31E2A00DB3429 /* MGLStyle.mm in Sources */,
@@ -1311,6 +1383,7 @@
DA6408D81DA4E5DA00908C90 /* MGLVectorStyleLayer.m in Sources */,
DA8F25B31D51CB270010E6B5 /* NSValue+MGLStyleAttributeAdditions.mm in Sources */,
DAE6C3911CC31E2A00DB3429 /* MGLPolygon.mm in Sources */,
+ 35C6DF851E214C0400ACA483 /* MGLDistanceFormatter.m in Sources */,
DAE6C39B1CC31E2A00DB3429 /* NSProcessInfo+MGLAdditions.m in Sources */,
DAE6C38F1CC31E2A00DB3429 /* MGLOfflineStorage.mm in Sources */,
DAED38601D62CED700D7640F /* NSURL+MGLAdditions.m in Sources */,
@@ -1346,9 +1419,9 @@
DAE6C3D61CC34C9900DB3429 /* MGLStyleTests.mm in Sources */,
DAEDC4371D606291000224FF /* MGLAttributionButtonTests.m in Sources */,
DA35A2B61CCA14D700E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
+ 35C6DF871E214C1800ACA483 /* MGLDistanceFormatterTests.m in Sources */,
DAE6C3D21CC34C9900DB3429 /* MGLGeometryTests.mm in Sources */,
DA87A9A41DCACC5000810D09 /* MGLSymbolStyleLayerTests.mm in Sources */,
- DAE6C3D51CC34C9900DB3429 /* MGLOfflineStorageTests.m in Sources */,
40E1601D1DF217D6005EA6D9 /* MGLStyleLayerTests.m in Sources */,
DA87A9A61DCACC5000810D09 /* MGLCircleStyleLayerTests.mm in Sources */,
DA87A99E1DC9DC2100810D09 /* MGLPredicateTests.mm in Sources */,
@@ -1362,6 +1435,7 @@
DA35A2A81CC9F41600E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
DAE7DEC41E24549F007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
DA87A9981DC9D88400810D09 /* MGLShapeSourceTests.mm in Sources */,
+ 55E2AD111E5B0A6900E8C587 /* MGLOfflineStorageTests.mm in Sources */,
3526EABD1DF9B19800006B43 /* MGLCodingTests.m in Sources */,
DA87A9A21DC9DCF100810D09 /* MGLFillStyleLayerTests.mm in Sources */,
3599A3E81DF70E2000E77FB2 /* MGLStyleValueTests.m in Sources */,
@@ -1388,6 +1462,26 @@
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
+ 96E027331E57C9A7004B8E66 /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 96E027321E57C9A7004B8E66 /* Base */,
+ 96E027341E57C9A9004B8E66 /* zh-Hans */,
+ 96E027351E57C9AB004B8E66 /* zh-Hant */,
+ 96E027361E57C9AC004B8E66 /* de */,
+ 96E027371E57C9B5004B8E66 /* fr */,
+ 96E027381E57C9B7004B8E66 /* ja */,
+ 96E027391E57C9B9004B8E66 /* sv */,
+ 96E0273A1E57C9BB004B8E66 /* vi */,
+ 96E0273B1E57C9BC004B8E66 /* pt-BR */,
+ 966091701E5BBFF700A9A03B /* es */,
+ 966091711E5BBFF900A9A03B /* pl */,
+ 966091721E5BBFFA00A9A03B /* uk */,
+ 966091731E5BBFFA00A9A03B /* lt */,
+ );
+ name = Localizable.strings;
+ sourceTree = "<group>";
+ };
DA839E9E1CC2E3400062CAFB /* MapDocument.xib */ = {
isa = PBXVariantGroup;
children = (
@@ -1417,6 +1511,17 @@
children = (
DA8933AC1CCD290700E68420 /* Base */,
DA88520F1E0A4D0D009D7AD6 /* zh-Hans */,
+ DAFBD0D51E3FA969000CD6BF /* zh-Hant */,
+ DAA32CA61E4C4849006F8D24 /* de */,
+ DAA32CAF1E4C4B0D006F8D24 /* fr */,
+ DAA32CB31E4C4CC3006F8D24 /* ja */,
+ DAA32CBA1E4C4F10006F8D24 /* sv */,
+ DAA32CC11E4C4F93006F8D24 /* vi */,
+ DA9C01311E4C7B9F00C4742A /* pt-BR */,
+ DA737ADF1E5914D300AD2CDE /* es */,
+ DA737AE41E5915B000AD2CDE /* pl */,
+ DA737AEC1E59180E00AD2CDE /* uk */,
+ DA1AC01E1E5B8826006DF1D6 /* lt */,
);
name = Localizable.strings;
sourceTree = "<group>";
@@ -1426,6 +1531,11 @@
children = (
DA8933B41CCD2C2500E68420 /* Base */,
DA8852101E0A4D3A009D7AD6 /* zh-Hans */,
+ DAFBD0D61E3FA983000CD6BF /* zh-Hant */,
+ DAA32CA71E4C486D006F8D24 /* de */,
+ DAA32CB21E4C4CB7006F8D24 /* ja */,
+ DAA32CC01E4C4F89006F8D24 /* vi */,
+ DA6023EF1E4CE8E500DBFF23 /* sv */,
);
name = Foundation.strings;
sourceTree = "<group>";
@@ -1434,6 +1544,13 @@
isa = PBXVariantGroup;
children = (
DA8933B71CCD2C2D00E68420 /* en */,
+ DAA32CA81E4C48B9006F8D24 /* de */,
+ DAA32CAE1E4C4B03006F8D24 /* fr */,
+ DA9C01301E4C7B9300C4742A /* pt-BR */,
+ DA6023F01E4CE8FF00DBFF23 /* sv */,
+ DA737ADE1E5914AD00AD2CDE /* es */,
+ DA737AE31E5915A500AD2CDE /* pl */,
+ DA1AC01F1E5B8904006DF1D6 /* uk */,
);
name = Foundation.stringsdict;
sourceTree = "<group>";
diff --git a/platform/macos/scripts/deploy-packages.sh b/platform/macos/scripts/deploy-packages.sh
index d0c545f8f5..8f61519244 100755
--- a/platform/macos/scripts/deploy-packages.sh
+++ b/platform/macos/scripts/deploy-packages.sh
@@ -9,7 +9,7 @@ set -u
# GITHUB_RELEASE=true: Upload to github
# BINARY_DIRECTORY=build/macos/deploy: Directory in which to save test packages
-# environment variables and dependencies:
+# environment variables and dependencies:
# - You must run "mbx auth ..." before running
# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
# - "wget" is required for downloading the zip files from s3
@@ -20,19 +20,19 @@ function finish { >&2 echo -en "\033[0m"; }
trap finish EXIT
buildPackageStyle() {
- local package=$1 style=""
+ local package=$1 style=""
if [[ ${#} -eq 2 ]]; then
style="$2"
- fi
+ fi
step "Building: make ${package} ${style}"
make ${package}
step "Publishing ${package} with ${style}"
local file_name=""
- if [ -z ${style} ]
+ if [ -z ${style} ]
then
- file_name=mapbox-macos-sdk-${PUBLISH_VERSION}.zip
+ file_name=mapbox-macos-sdk-${PUBLISH_VERSION}.zip
else
- file_name=mapbox-macos-sdk-${PUBLISH_VERSION}-${style}.zip
+ file_name=mapbox-macos-sdk-${PUBLISH_VERSION}-${style}.zip
fi
step "Compressing ${file_name}…"
cd build/macos/pkg
@@ -98,7 +98,7 @@ step "Deploying version ${PUBLISH_VERSION}…"
if [[ ${#} -eq 3 && $3 == "-g" ]]; then
GITHUB_RELEASE=true
fi
-
+
make clean && make distclean
mkdir -p ${BINARY_DIRECTORY}
diff --git a/platform/macos/sdk/de.lproj/Localizable.strings b/platform/macos/sdk/de.lproj/Localizable.strings
new file mode 100644
index 0000000000..fe3d979a31
--- /dev/null
+++ b/platform/macos/sdk/de.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Vergrößern";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Verkleinern";
+
diff --git a/platform/macos/sdk/es.lproj/Localizable.strings b/platform/macos/sdk/es.lproj/Localizable.strings
new file mode 100644
index 0000000000..4ebb97b440
--- /dev/null
+++ b/platform/macos/sdk/es.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Acercar";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Alejar";
+
diff --git a/platform/macos/sdk/fr.lproj/Localizable.strings b/platform/macos/sdk/fr.lproj/Localizable.strings
new file mode 100644
index 0000000000..34e085ef2b
--- /dev/null
+++ b/platform/macos/sdk/fr.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Zoomer";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Dézoomer";
+
diff --git a/platform/macos/sdk/ja.lproj/Localizable.strings b/platform/macos/sdk/ja.lproj/Localizable.strings
new file mode 100644
index 0000000000..def56d1a9d
--- /dev/null
+++ b/platform/macos/sdk/ja.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "ズームイン";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "ズームアウト";
+
diff --git a/platform/macos/sdk/lt.lproj/Localizable.strings b/platform/macos/sdk/lt.lproj/Localizable.strings
new file mode 100644
index 0000000000..8e93c86963
--- /dev/null
+++ b/platform/macos/sdk/lt.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Priartinti";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Nutolinti";
+
diff --git a/platform/macos/sdk/pl.lproj/Localizable.strings b/platform/macos/sdk/pl.lproj/Localizable.strings
new file mode 100644
index 0000000000..d86155cbde
--- /dev/null
+++ b/platform/macos/sdk/pl.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Powiększ";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Pomniejsz";
+
diff --git a/platform/macos/sdk/pt-BR.lproj/Localizable.strings b/platform/macos/sdk/pt-BR.lproj/Localizable.strings
new file mode 100644
index 0000000000..c7490ec8d8
--- /dev/null
+++ b/platform/macos/sdk/pt-BR.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Aumentar Zoom";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Reduzir Zoom";
+
diff --git a/platform/macos/sdk/sv.lproj/Localizable.strings b/platform/macos/sdk/sv.lproj/Localizable.strings
new file mode 100644
index 0000000000..34841108a7
--- /dev/null
+++ b/platform/macos/sdk/sv.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Zooma in";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Zooma ut";
+
diff --git a/platform/macos/sdk/uk.lproj/Localizable.strings b/platform/macos/sdk/uk.lproj/Localizable.strings
new file mode 100644
index 0000000000..1be17a4d49
--- /dev/null
+++ b/platform/macos/sdk/uk.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Збільшити";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Зменшити";
+
diff --git a/platform/macos/sdk/vi.lproj/Localizable.strings b/platform/macos/sdk/vi.lproj/Localizable.strings
new file mode 100644
index 0000000000..086820b034
--- /dev/null
+++ b/platform/macos/sdk/vi.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "Phóng to";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "Thu nhỏ";
+
diff --git a/platform/macos/sdk/zh-Hant.lproj/Localizable.strings b/platform/macos/sdk/zh-Hant.lproj/Localizable.strings
new file mode 100644
index 0000000000..4447371d71
--- /dev/null
+++ b/platform/macos/sdk/zh-Hant.lproj/Localizable.strings
@@ -0,0 +1,15 @@
+/* Accessibility title */
+"MAP_A11Y_TITLE" = "Mapbox";
+
+/* Label of Zoom In button */
+"ZOOM_IN_LABEL" = "+";
+
+/* Tooltip of Zoom In button */
+"ZOOM_IN_TOOLTIP" = "放大";
+
+/* Label of Zoom Out button; U+2212 MINUS SIGN */
+"ZOOM_OUT_LABEL" = "−";
+
+/* Tooltip of Zoom Out button */
+"ZOOM_OUT_TOOLTIP" = "縮小";
+
diff --git a/platform/macos/src/MGLAnnotationImage.h b/platform/macos/src/MGLAnnotationImage.h
index 0f248c721c..d7336133d1 100644
--- a/platform/macos/src/MGLAnnotationImage.h
+++ b/platform/macos/src/MGLAnnotationImage.h
@@ -17,7 +17,7 @@ MGL_EXPORT
/**
Initializes and returns a new annotation image object.
-
+
@param image The image to display for the annotation.
@param reuseIdentifier The string that identifies this annotation image in the
reuse queue.
@@ -34,11 +34,11 @@ MGL_EXPORT
/**
The string that identifies this annotation image in the reuse queue.
(read-only)
-
+
You specify the reuse identifier when you create the image object. You use this
type later to retrieve an annotation image object that was created previously
but which is currently unused because its annotation is not on-screen.
-
+
If you define distinctly different types of annotations (with distinctly
different annotation images to go with them), you can differentiate between the
annotation types by specifying different reuse identifiers for each one.
@@ -47,7 +47,7 @@ MGL_EXPORT
/**
A Boolean value indicating whether the annotation is selectable.
-
+
The default value of this property is `YES`. If the value of this property is
`NO`, the annotation image ignores click events and cannot be selected.
*/
@@ -55,7 +55,7 @@ MGL_EXPORT
/**
The cursor that appears above any annotation using this annotation image.
-
+
By default, this property is set to `nil`, representing the current cursor.
*/
@property (nonatomic, nullable) NSCursor *cursor;
diff --git a/platform/macos/src/MGLAnnotationImage.m b/platform/macos/src/MGLAnnotationImage.m
index d19dbe5dfc..8d715b427b 100644
--- a/platform/macos/src/MGLAnnotationImage.m
+++ b/platform/macos/src/MGLAnnotationImage.m
@@ -47,9 +47,9 @@
- (BOOL)isEqual:(id)other {
if (self == other) return YES;
if (![other isKindOfClass:[MGLAnnotationImage class]]) return NO;
-
+
MGLAnnotationImage *otherAnnotationImage = other;
-
+
return ((!_reuseIdentifier && !otherAnnotationImage.reuseIdentifier) || [_reuseIdentifier isEqualToString:otherAnnotationImage.reuseIdentifier])
&& _selectable == otherAnnotationImage.selectable
&& ((!_cursor && !otherAnnotationImage.cursor) || [_cursor isEqual:otherAnnotationImage.cursor])
diff --git a/platform/macos/src/MGLAttributionButton.mm b/platform/macos/src/MGLAttributionButton.mm
index ed8bb18a66..3df415f60d 100644
--- a/platform/macos/src/MGLAttributionButton.mm
+++ b/platform/macos/src/MGLAttributionButton.mm
@@ -10,25 +10,25 @@
if (self = [super initWithFrame:NSZeroRect]) {
self.bordered = NO;
self.bezelStyle = NSRegularSquareBezelStyle;
-
+
// Extract any prefix consisting of intellectual property symbols.
NSScanner *scanner = [NSScanner scannerWithString:info.title.string];
NSCharacterSet *symbolSet = [NSCharacterSet characterSetWithCharactersInString:@"©℗®℠™ &"];
NSString *symbol;
[scanner scanCharactersFromSet:symbolSet intoString:&symbol];
-
+
// Remove the underline from the symbol for aesthetic reasons.
NSMutableAttributedString *title = info.title.mutableCopy;
[title removeAttribute:NSUnderlineStyleAttributeName range:NSMakeRange(0, symbol.length)];
-
+
self.attributedTitle = title;
[self sizeToFit];
-
+
_URL = info.URL;
if (_URL) {
self.toolTip = _URL.absoluteString;
}
-
+
self.target = self;
self.action = @selector(openURL:);
}
diff --git a/platform/macos/src/MGLMapView+IBAdditions.h b/platform/macos/src/MGLMapView+IBAdditions.h
index 81f4506a57..8a4a90917b 100644
--- a/platform/macos/src/MGLMapView+IBAdditions.h
+++ b/platform/macos/src/MGLMapView+IBAdditions.h
@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
// underscores for display.
/** URL of the style currently displayed in the receiver.
-
+
The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s
map ID (`mapbox://styles/<user>/<style>`), or a path to a local file
relative to the application’s resource path. Leave this field blank for the
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index efe83d1573..4d1a2fc2c4 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -19,11 +19,11 @@ NS_ASSUME_NONNULL_BEGIN
/**
An interactive, customizable map view with an interface similar to the one
provided by Apple’s MapKit.
-
+
Using `MGLMapView`, you can embed the map inside a view, allow users to
manipulate it with standard gestures, animate the map between different
viewpoints, and present information in the form of annotations and overlays.
-
+
The map view loads scalable vector tiles that conform to the
<a href="https://github.com/mapbox/vector-tile-spec">Mapbox Vector Tile Specification</a>.
It styles them with a style that conforms to the
@@ -31,20 +31,35 @@ NS_ASSUME_NONNULL_BEGIN
Such styles can be designed in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
mapbox.com.
-
+
A collection of Mapbox-hosted styles is available through the `MGLStyle` class.
These basic styles use
<a href="https://www.mapbox.com/developers/vector-tiles/mapbox-streets">Mapbox Streets</a>
or <a href="https://www.mapbox.com/satellite/">Mapbox Satellite</a> data
sources, but you can specify a custom style that makes use of your own data.
-
+
Mapbox-hosted vector tiles and styles require an API access token, which you
can obtain from the
<a href="https://www.mapbox.com/studio/account/tokens/">Mapbox account page</a>.
Access tokens associate requests to Mapbox’s vector tile and style APIs with
your Mapbox account. They also deter other developers from using your styles
without your permission.
-
+
+ Adding your own gesture recognizer to `MGLMapView` will block the corresponding
+ gesture recognizer built into `MGLMapView`. To avoid conflicts, define which
+ gesture recognizer takes precedence. For example, you can subclass
+ `NSClickGestureRecognizer` and override `-[NSGestureRecognizer shouldRequireFailureOfGestureRecognizer:]`,
+ so that your subclass will be invoked only if the default `MGLMapView` click
+ gesture recognizer fails:
+
+ ```swift
+ class MapClickGestureRecognizer: NSClickGestureRecognizer {
+ override func shouldRequireFailure(of otherGestureRecognizer: NSGestureRecognizer) -> Bool {
+ return otherGestureRecognizer is NSClickGestureRecognizer
+ }
+ }
+ ```
+
@note You are responsible for getting permission to use the map data and for
ensuring that your use adheres to the relevant terms of use.
*/
@@ -56,7 +71,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Initializes and returns a newly allocated map view with the specified frame and
the default style.
-
+
@param frame The frame for the view, measured in points.
@return An initialized map view.
*/
@@ -65,7 +80,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Initializes and returns a newly allocated map view with the specified frame and
style URL.
-
+
@param frame The frame for the view, measured in points.
@param styleURL URL of the map style to display. The URL may be a full HTTP or
HTTPS URL, a Mapbox URL indicating the style’s map ID
@@ -79,7 +94,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The receiver’s delegate.
-
+
A map view sends messages to its delegate to notify it of changes to its
contents or the viewpoint. The delegate also provides information about
annotations displayed on the map, such as the styles to apply to individual
@@ -91,36 +106,36 @@ MGL_EXPORT IB_DESIGNABLE
/**
The style currently displayed in the receiver.
-
+
Unlike the `styleURL` property, this property is set to an object that allows
you to manipulate every aspect of the style locally.
-
+
If the style is loading, this property is set to `nil` until the style finishes
loading. If the style has failed to load, this property is set to `nil`.
Because the style loads asynchronously, you should manipulate it in the
`-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
`-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method. It is not possible
to manipulate the style before it has finished loading.
-
+
@note The default styles provided by Mapbox contain sources and layers with
identifiers that will change over time. Applications that use APIs that
manipulate a style's sources and layers must first set the style URL to an
explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`.
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
/**
URL of the style currently displayed in the receiver.
-
+
The URL may be a full HTTP or HTTPS URL, a Mapbox URL indicating the style’s
map ID (`mapbox://styles/<user>/<style>`), or a path to a local file relative
to the application’s resource path.
-
+
If you set this property to `nil`, the receiver will use the default style and
this property will automatically be set to that style’s URL.
-
+
If you want to modify the current style without replacing it outright, or if
you want to introspect individual style attributes, use the `style` property.
*/
@@ -128,7 +143,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Reloads the style.
-
+
You do not normally need to call this method. The map view automatically
responds to changes in network connectivity by reloading the style. You may
need to call this method if you change the access token after a style has
@@ -149,7 +164,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The Mapbox logo, positioned in the lower-left corner.
-
+
@note The Mapbox terms of service, which governs the use of Mapbox-hosted
vector tiles and styles,
<a href="https://www.mapbox.com/help/mapbox-logo/">requires</a> most Mapbox
@@ -161,7 +176,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
A view showing legally required copyright notices, positioned along the bottom
of the map view, to the left of the Mapbox logo.
-
+
@note The Mapbox terms of service, which governs the use of Mapbox-hosted
vector tiles and styles,
<a href="https://www.mapbox.com/help/attribution/">requires</a> these
@@ -176,10 +191,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
The geographic coordinate at the center of the map view.
-
+
Changing the value of this property centers the map on the new coordinate
without changing the current zoom level.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setCenterCoordinate:animated:` method
instead.
@@ -188,10 +203,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
Changes the center coordinate of the map and optionally animates the change.
-
+
Changing the center coordinate centers the map on the new coordinate without
changing the current zoom level.
-
+
@param coordinate The new center coordinate for the map.
@param animated Specify `YES` if you want the map view to scroll to the new
location or `NO` if you want the map to display the new location
@@ -201,12 +216,12 @@ MGL_EXPORT IB_DESIGNABLE
/**
The zoom level of the receiver.
-
+
In addition to affecting the visual size and detail of features on the map, the
zoom level affects the size of the vector tiles that are loaded. At zoom level
0, each tile covers the entire world map; at zoom level 1, it covers ¼ of the
world; at zoom level 2, <sup>1</sup>⁄<sub>16</sub> of the world, and so on.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setZoomLevel:animated:` method instead.
*/
@@ -214,34 +229,34 @@ MGL_EXPORT IB_DESIGNABLE
/**
The minimum zoom level at which the map can be shown.
-
+
Depending on the map view’s aspect ratio, the map view may be prevented from
reaching the minimum zoom level, in order to keep the map from repeating within
the current viewport.
-
+
If the value of this property is greater than that of the `maximumZoomLevel`
property, the behavior is undefined.
-
+
The default value of this property is 0.
*/
@property (nonatomic) double minimumZoomLevel;
/**
The maximum zoom level the map can be shown at.
-
+
If the value of this property is smaller than that of the `minimumZoomLevel`
property, the behavior is undefined.
-
+
The default value of this property is 20.
*/
@property (nonatomic) double maximumZoomLevel;
/**
Changes the zoom level of the map and optionally animates the change.
-
+
Changing the zoom level scales the map without changing the current center
coordinate.
-
+
@param zoomLevel The new zoom level for the map.
@param animated Specify `YES` if you want the map view to animate the change
to the new zoom level or `NO` if you want the map to display the new zoom
@@ -251,11 +266,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
The heading of the map, measured in degrees clockwise from true north.
-
+
The value `0` means that the top edge of the map view corresponds to true
north. The value `90` means the top of the map is pointing due east. The value
`180` means the top of the map points due south, and so on.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setDirection:animated:` method instead.
*/
@@ -263,10 +278,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
Changes the heading of the map and optionally animates the change.
-
+
Changing the heading rotates the map without changing the current center
coordinate or zoom level.
-
+
@param direction The heading of the map, measured in degrees clockwise from
true north.
@param animated Specify `YES` if you want the map view to animate the change
@@ -283,7 +298,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition animation.
-
+
@param camera The new viewpoint.
@param animated Specify `YES` if you want the map view to animate the change to
the new viewpoint or `NO` if you want the map to display the new viewpoint
@@ -294,7 +309,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition duration and timing function.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -310,10 +325,10 @@ MGL_EXPORT IB_DESIGNABLE
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and a default duration based on the length of the flight
path.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param completion The block to execute after the animation finishes.
*/
@@ -322,10 +337,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and an optional transition duration.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -338,10 +353,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
Moves the viewpoint to a different location using a transition animation that
evokes powered flight and an optional transition duration and peak altitude.
-
+
The transition animation seamlessly incorporates zooming and panning to help
the user find his or her bearings even after traversing a great distance.
-
+
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
animation should take. Specify `0` to jump to the new viewpoint
@@ -357,7 +372,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The geographic coordinate bounds visible in the receiver’s viewport.
-
+
Changing the value of this property updates the receiver immediately. If you
want to animate the change, use the `-setVisibleCoordinateBounds:animated:`
method instead.
@@ -367,7 +382,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit the given coordinate bounds, optionally
animating the change.
-
+
@param bounds The bounds that the viewport will show in its entirety.
@param animated Specify `YES` to animate the change by smoothly scrolling and
zooming or `NO` to immediately display the given bounds.
@@ -377,7 +392,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Changes the receiver’s viewport to fit the given coordinate bounds and
optionally some additional padding on each side.
-
+
@param bounds The bounds that the viewport will show in its entirety.
@param insets The minimum padding (in screen points) that will be visible
around the given coordinate bounds.
@@ -417,7 +432,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns the camera that best fits the given coordinate bounds.
-
+
@param bounds The coordinate bounds to fit to the receiver’s viewport.
@return A camera object centered on the same location as the coordinate bounds
with zoom level as high (close to the ground) as possible while still
@@ -429,7 +444,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns the camera that best fits the given coordinate bounds, optionally with
some additional padding on each side.
-
+
@param bounds The coordinate bounds to fit to the receiver’s viewport.
@param insets The minimum padding (in screen points) that would be visible
around the returned camera object if it were set as the receiver’s camera.
@@ -443,13 +458,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value indicating whether the receiver automatically adjusts its
content insets.
-
+
When the value of this property is `YES`, the map view automatically updates
its `contentInsets` property to account for any overlapping title bar or
toolbar. To overlap with the title bar or toolbar, the containing window’s
style mask must have `NSFullSizeContentViewWindowMask` set, and the title bar
must not be transparent.
-
+
The default value of this property is `YES`.
*/
@property (nonatomic, assign) BOOL automaticallyAdjustsContentInsets;
@@ -457,16 +472,16 @@ MGL_EXPORT IB_DESIGNABLE
/**
The distance from the edges of the map view’s frame to the edges of the map
view’s logical viewport.
-
+
When the value of this property is equal to `NSEdgeInsetsZero`, viewport
properties such as `centerCoordinate` assume a viewport that matches the map
view’s frame. Otherwise, those properties are inset, excluding part of the
frame from the viewport. For instance, if the only the top edge is inset, the
map center is effectively shifted downward.
-
+
When the value of the `automaticallyAdjustsContentInsets` property is `YES`,
the value of this property may be overridden at any time.
-
+
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setContentInsets:animated:` method
instead.
@@ -476,16 +491,16 @@ MGL_EXPORT IB_DESIGNABLE
/**
Sets the distance from the edges of the map view’s frame to the edges of the
map view’s logical viewport, with an optional transition animation.
-
+
When the value of this property is equal to `NSEdgeInsetsZero`, viewport
properties such as `centerCoordinate` assume a viewport that matches the map
view’s frame. Otherwise, those properties are inset, excluding part of the
frame from the viewport. For instance, if the only the top edge is inset, the
map center is effectively shifted downward.
-
+
When the value of the `automaticallyAdjustsContentInsets` property is `YES`,
the value of this property may be overridden at any time.
-
+
@param contentInsets The new values to inset the content by.
@param animated Specify `YES` if you want the map view to animate the change to
the content insets or `NO` if you want the map to inset the content
@@ -498,13 +513,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value that determines whether the user may zoom the map in and out,
changing the zoom level.
-
+
When this property is set to `YES`, the default, the user may zoom the map in
and out by pinching two fingers, by using a scroll wheel on a traditional
mouse, or by dragging the mouse cursor up and down while holding down the Shift
key. When the receiver has focus, the user may also zoom by pressing the up and
down arrow keys while holding down the Option key.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the map zoom
programmatically.
@@ -514,11 +529,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value that determines whether the user may scroll around the map,
changing the center coordinate.
-
+
When this property is set to `YES`, the default, the user may scroll the map by
swiping with two fingers or dragging the mouse cursor. When the receiver has
focus, the user may also scroll around the map by pressing the arrow keys.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the map location
programmatically.
@@ -528,13 +543,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value that determines whether the user may rotate the map, changing
the direction.
-
+
When this property is set to `YES`, the default, the user may rotate the map by
moving two fingers in a circular motion or by dragging the mouse cursor left
and right while holding down the Option key. When the receiver has focus, the
user may also zoom by pressing the left and right arrow keys while holding down
the Option key.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still rotate the map programmatically.
*/
@@ -543,10 +558,10 @@ MGL_EXPORT IB_DESIGNABLE
/**
A Boolean value that determines whether the user may tilt of the map, changing
the pitch.
-
+
When this property is set to `YES`, the default, the user may rotate the map by
dragging the mouse cursor up and down while holding down the Option key.
-
+
This property controls only user interactions with the map. If you set the
value of this property to `NO`, you may still change the pitch of the map
programmatically.
@@ -557,7 +572,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The complete list of annotations associated with the receiver. (read-only)
-
+
The objects in this array must adopt the `MGLAnnotation` protocol. If no
annotations are associated with the map view, the value of this property is
`nil`.
@@ -566,13 +581,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
Adds an annotation to the map view.
-
+
@note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
cannot be added to the map view at this time. Nor can `MGLMultiPoint`
objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any
multipoint, multipolyline, multipolygon, or shape collection object that is
specified is silently ignored.
-
+
@param annotation The annotation object to add to the receiver. This object
must conform to the `MGLAnnotation` protocol. The map view retains the
annotation object.
@@ -581,13 +596,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
Adds an array of annotations to the map view.
-
+
@note `MGLMultiPolyline`, `MGLMultiPolygon`, and `MGLShapeCollection` objects
cannot be added to the map view at this time. Nor can `MGLMultiPoint`
objects that are not instances of `MGLPolyline` or `MGLPolygon`. Any
multipoint, multipolyline, multipolygon, or shape collection objects that
are specified are silently ignored.
-
+
@param annotations An array of annotation objects. Each object in the array
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
@@ -597,7 +612,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The complete list of annotations associated with the receiver that are
currently visible.
-
+
The objects in this array must adopt the `MGLAnnotation` protocol. If no
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`.
@@ -606,11 +621,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
Removes an annotation from the map view, deselecting it if it is selected.
-
+
Removing an annotation object dissociates it from the map view entirely,
preventing it from being displayed on the map. Thus you would typically call
this method only when you want to hide or delete a given annotation.
-
+
@param annotation The annotation object to remove. This object must conform to
the `MGLAnnotation` protocol.
*/
@@ -619,11 +634,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
Removes an array of annotations from the map view, deselecting any selected
annotations in the array.
-
+
Removing annotation objects dissociates them from the map view entirely,
preventing them from being displayed on the map. Thus you would typically call
this method only when you want to hide or delete the given annotations.
-
+
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
@@ -631,11 +646,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns a reusable annotation image object associated with its identifier.
-
+
For performance reasons, you should generally reuse `MGLAnnotationImage`
objects for identical-looking annotations in your map views. Dequeueing saves
time and memory during performance-critical operations such as scrolling.
-
+
@param identifier A string identifying the annotation image to be reused. This
string is the same one you specify when initially returning the annotation
image object using the `-mapView:imageForAnnotation:` method.
@@ -647,7 +662,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns the list of annotations associated with the receiver that intersect with
the given rectangle.
-
+
@param rect A rectangle expressed in the map view’s coordinate system.
@return An array of objects that adopt the `MGLAnnotation` protocol or `nil` if
no annotations associated with the map view are currently visible in the
@@ -659,7 +674,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The currently selected annotations.
-
+
Assigning a new array to this property selects only the first annotation in the
array.
*/
@@ -667,30 +682,30 @@ MGL_EXPORT IB_DESIGNABLE
/**
Selects an annotation and displays a callout popover for it.
-
+
If the given annotation is not visible within the current viewport, this method
has no effect.
-
+
@param annotation The annotation object to select.
*/
- (void)selectAnnotation:(id <MGLAnnotation>)annotation;
/**
Deselects an annotation and hides its callout popover.
-
+
@param annotation The annotation object to deselect.
*/
- (void)deselectAnnotation:(nullable id <MGLAnnotation>)annotation;
/**
A common view controller for managing a callout popover’s content view.
-
+
Like any instance of `NSPopover`, an annotation callout manages its contents
with a view controller. The annotation object is the view controller’s
represented object. This means that you can bind controls in the view
controller’s content view to KVO-compliant properties of the annotation object,
such as `title` and `subtitle`.
-
+
This property defines a common view controller that is used for every
annotation’s callout view. If you set this property to `nil`, a default view
controller will be used that manages a simple title label and subtitle label.
@@ -704,7 +719,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns a point annotation located at the given point.
-
+
@param point A point in the view’s coordinate system.
@return A point annotation whose annotation image coincides with the point. If
multiple point annotations coincide with the point, the return value is the
@@ -716,9 +731,9 @@ MGL_EXPORT IB_DESIGNABLE
/**
Adds a single overlay to the map.
-
+
To remove an overlay from a map, use the `-removeOverlay:` method.
-
+
@param overlay The overlay object to add. This object must conform to the
`MGLOverlay` protocol.
*/
@@ -726,9 +741,9 @@ MGL_EXPORT IB_DESIGNABLE
/**
Adds an array of overlays to the map.
-
+
To remove multiple overlays from a map, use the `-removeOverlays:` method.
-
+
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
@@ -736,19 +751,19 @@ MGL_EXPORT IB_DESIGNABLE
/**
Removes a single overlay from the map.
-
+
If the specified overlay is not currently associated with the map view, this
method does nothing.
-
+
@param overlay The overlay object to remove.
*/
- (void)removeOverlay:(id <MGLOverlay>)overlay;
/**
Removes an array of overlays from the map.
-
+
If a given overlay object is not associated with the map view, it is ignored.
-
+
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
@@ -758,12 +773,12 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with a given point.
-
+
This method may return features from any of the map’s style layers. To restrict
the search to a particular layer or layers, use the
`-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
information about searching for map features, see that method’s documentation.
-
+
@param point A point expressed in the map view’s coordinate system.
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
@@ -773,13 +788,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with a given point,
restricted to the given style layers.
-
+
Each object in the returned array represents a feature rendered by the
current style and provides access to attributes specified by the relevant
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
The returned array includes features specified in vector and GeoJSON tile
sources but does not include anything from raster, image, or video sources.
-
+
Only visible features are returned. For example, suppose the current style uses
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
@@ -792,26 +807,26 @@ MGL_EXPORT IB_DESIGNABLE
attributes). The dictionary contains only the attributes provided by the
tile source; it does not include computed attribute values or rules about how
the feature is rendered by the current style.
-
+
The returned array is sorted by z-order, starting with the topmost rendered
feature and ending with the bottommost rendered feature. A feature that is
rendered multiple times due to wrapping across the antimeridian at low zoom
levels is included only once, subject to the caveat that follows.
-
+
Features come from tiled vector data or GeoJSON data that is converted to tiles
internally, so feature geometries are clipped at tile boundaries and features
may appear duplicated across tiles. For example, suppose the specified point
lies along a road that spans the screen. The resulting array includes those
parts of the road that lie within the map tile that contain the specified
point, even if the road extends into other tiles.
-
+
To find out the layer names in a particular style, view the style in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
@@ -828,12 +843,12 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with the given
rectangle.
-
+
This method may return features from any of the map’s style layers. To restrict
the search to a particular layer or layers, use the
`-visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:` method. For more
information about searching for map features, see that method’s documentation.
-
+
@param rect A rectangle expressed in the map view’s coordinate system.
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
@@ -843,13 +858,13 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns an array of rendered map features that intersect with the given
rectangle, restricted to the given style layers.
-
+
Each object in the returned array represents a feature rendered by the
current style and provides access to attributes specified by the relevant
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources">tile sources</a>.
The returned array includes features specified in vector and GeoJSON tile
sources but does not include anything from raster, image, or video sources.
-
+
Only visible features are returned. For example, suppose the current style uses
the
<a href="https://www.mapbox.com/vector-tiles/mapbox-streets/">Mapbox Streets source</a>,
@@ -862,12 +877,12 @@ MGL_EXPORT IB_DESIGNABLE
contains only the attributes provided by the tile source; it does not include
computed attribute values or rules about how the feature is rendered by the
current style.
-
+
The returned array is sorted by z-order, starting with the topmost rendered
feature and ending with the bottommost rendered feature. A feature that is
rendered multiple times due to wrapping across the antimeridian at low zoom
levels is included only once, subject to the caveat that follows.
-
+
Features come from tiled vector data or GeoJSON data that is converted to tiles
internally, so feature geometries are clipped at tile boundaries and features
may appear duplicated across tiles. For example, suppose the specified
@@ -875,14 +890,14 @@ MGL_EXPORT IB_DESIGNABLE
includes those parts of the road that lie within the map tiles covering the
specified rectangle, even if the road extends into other tiles. The portion of
the road within each map tile is included individually.
-
+
To find out the layer names in a particular style, view the style in
<a href="https://www.mapbox.com/studio/">Mapbox Studio</a>.
-
+
@note Layer identifiers are not guaranteed to exist across styles or different
versions of the same style. Applications that use this API must first set the
style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`'s “Style URL”
+ `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
inspectable in Interface Builder, or a manually constructed `NSURL`. This
approach also avoids layer identifer name changes that will occur in the default
style’s layers over time.
@@ -901,7 +916,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Converts a geographic coordinate to a point in the given view’s coordinate
system.
-
+
@param coordinate The geographic coordinate to convert.
@param view The view in whose coordinate system the returned point should be
expressed. If this parameter is `nil`, the returned point is expressed in
@@ -915,7 +930,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Converts a point in the given view’s coordinate system to a geographic
coordinate.
-
+
@param point The point to convert.
@param view The view in whose coordinate system the point is expressed.
@return The geographic coordinate at the given point.
@@ -925,7 +940,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Converts a geographic bounding box to a rectangle in the given view’s
coordinate system.
-
+
@param bounds The geographic bounding box to convert.
@param view The view in whose coordinate system the returned rectangle should
be expressed. If this parameter is `nil`, the returned rectangle is
@@ -937,7 +952,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
Converts a rectangle in the given view’s coordinate system to a geographic
bounding box.
-
+
@param rect The rectangle to convert.
@param view The view in whose coordinate system the rectangle is expressed.
@return The geographic bounding box coextensive with the given rectangle.
@@ -947,11 +962,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
Returns the distance spanned by one point in the map view’s coordinate system
at the given latitude and current zoom level.
-
+
The distance between points decreases as the latitude approaches the poles.
This relationship parallels the relationship between longitudinal coordinates
at different latitudes.
-
+
@param latitude The latitude of the geographic coordinate represented by the
point.
@return The distance in meters spanned by a single point.
@@ -963,11 +978,11 @@ MGL_EXPORT IB_DESIGNABLE
/**
Opens one or more webpages in the default Web browser in which the user can
provide feedback about the map data.
-
+
You should add a menu item to the Help menu of your application that invokes
this method. Title it “Improve This Map” or similar. Set its target to the
first responder and its action to `giveFeedback:`.
-
+
This map view searches the current style’s sources for webpages to open.
Specifically, each source’s tile set has an `attribution` property containing
HTML code; if an <code>&lt;a></code> tag (link) within that code has an
@@ -981,7 +996,7 @@ MGL_EXPORT IB_DESIGNABLE
/**
The options that determine which debugging aids are shown on the map.
-
+
These options are all disabled by default and should remain disabled in
released software for performance and aesthetic reasons.
*/
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index e9d8fc5f45..827da35076 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -11,6 +11,7 @@
#import "MGLMultiPoint_Private.h"
#import "MGLOfflineStorage_Private.h"
#import "MGLStyle_Private.h"
+#import "MGLFoundation_Private.h"
#import "MGLAccountManager.h"
#import "MGLMapCamera.h"
@@ -35,6 +36,7 @@
#import <mbgl/util/constants.hpp>
#import <mbgl/util/chrono.hpp>
#import <mbgl/util/run_loop.hpp>
+#import <mbgl/util/shared_thread_pool.hpp>
#import <map>
#import <unordered_map>
@@ -105,11 +107,6 @@ NSImage *MGLDefaultMarkerImage() {
return [[NSImage alloc] initWithContentsOfFile:path];
}
-/// Initializes the run loop shim that lives on the main thread.
-void MGLinitializeRunLoop() {
- static mbgl::util::RunLoop mainRunLoop;
-}
-
/// Converts a media timing function into a unit bezier object usable in mbgl.
mbgl::util::UnitBezier MGLUnitBezierForMediaTimingFunction(CAMediaTimingFunction *function) {
if (!function) {
@@ -151,7 +148,7 @@ public:
/// Cross-platform map view controller.
mbgl::Map *_mbglMap;
MGLMapViewImpl *_mbglView;
- mbgl::ThreadPool *_mbglThreadPool;
+ std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
NSPanGestureRecognizer *_panGestureRecognizer;
NSMagnificationGestureRecognizer *_magnificationGestureRecognizer;
@@ -193,6 +190,9 @@ public:
/// True if the view is currently printing itself.
BOOL _isPrinting;
+
+ /// reachability instance
+ MGLReachability *_reachability;
}
#pragma mark Lifecycle
@@ -231,7 +231,11 @@ public:
- (void)awakeFromNib {
[super awakeFromNib];
- self.styleURL = nil;
+ // If the Style URL inspectable was not set, make sure to go through
+ // -setStyleURL: to load the default style.
+ if (_mbglMap->getStyleURL().empty()) {
+ self.styleURL = nil;
+ }
}
+ (NSArray *)restorableStateKeyPaths {
@@ -239,8 +243,6 @@ public:
}
- (void)commonInit {
- MGLinitializeRunLoop();
-
_isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
// Set up cross-platform controllers and resources.
@@ -260,7 +262,7 @@ public:
mbgl::DefaultFileSource* mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource;
- _mbglThreadPool = new mbgl::ThreadPool(4);
+ _mbglThreadPool = mbgl::sharedThreadPool();
_mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default);
[self validateTileCacheSize];
@@ -269,11 +271,11 @@ public:
self.layer = _isTargetingInterfaceBuilder ? [CALayer layer] : [MGLOpenGLLayer layer];
// Notify map object when network reachability status changes.
- MGLReachability *reachability = [MGLReachability reachabilityForInternetConnection];
- reachability.reachableBlock = ^(MGLReachability *) {
+ _reachability = [MGLReachability reachabilityForInternetConnection];
+ _reachability.reachableBlock = ^(MGLReachability *) {
mbgl::NetworkStatus::Reachable();
};
- [reachability startNotifier];
+ [_reachability startNotifier];
// Install ornaments and gesture recognizers.
[self installZoomControls];
@@ -432,7 +434,7 @@ public:
}
attributionView.subviews = @[];
[attributionView removeConstraints:attributionView.constraints];
-
+
// Make the whole string mini by default.
// Force links to be black, because the default blue is distracting.
CGFloat miniSize = [NSFont systemFontSizeForControlSize:NSMiniControlSize];
@@ -442,7 +444,7 @@ public:
if (info.feedbackLink) {
continue;
}
-
+
// For each attribution, add a borderless button that responds to clicks
// and feels like a hyperlink.
NSButton *button = [[MGLAttributionButton alloc] initWithAttributionInfo:info];
@@ -479,7 +481,7 @@ public:
multiplier:1
constant:0]];
}
-
+
if (attributionInfos.count) {
[attributionView addConstraint:
[NSLayoutConstraint constraintWithItem:attributionView
@@ -493,6 +495,10 @@ public:
}
- (void)dealloc {
+
+ [_reachability stopNotifier];
+
+
[self.window removeObserver:self forKeyPath:@"contentLayoutRect"];
[self.window removeObserver:self forKeyPath:@"titlebarAppearsTransparent"];
@@ -511,10 +517,6 @@ public:
delete _mbglView;
_mbglView = nullptr;
}
- if (_mbglThreadPool) {
- delete _mbglThreadPool;
- _mbglThreadPool = nullptr;
- }
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(__unused NSDictionary *)change context:(void *)context {
@@ -611,16 +613,17 @@ public:
if (_isTargetingInterfaceBuilder) {
return;
}
-
+
// Default to Streets.
if (!styleURL) {
- // An access token is required to load any default style, including
- // Streets.
- if (![MGLAccountManager accessToken]) {
- return;
- }
styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
}
+
+ // An access token is required to load any default style, including Streets.
+ if (![MGLAccountManager accessToken] && [styleURL.scheme isEqualToString:@"mapbox"]) {
+ NSLog(@"Cannot set the style URL to %@ because no access token has been specified.", styleURL);
+ return;
+ }
styleURL = styleURL.mgl_URLByStandardizingScheme;
self.style = nil;
@@ -787,9 +790,7 @@ public:
if (_isPrinting) {
_isPrinting = NO;
- std::string png = encodePNG(_mbglView->readStillImage());
- NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
- NSImage *image = [[NSImage alloc] initWithData:data];
+ NSImage *image = [[NSImage alloc] initWithMGLPremultipliedImage:_mbglView->readStillImage()];
[self performSelector:@selector(printWithImage:) withObject:image afterDelay:0];
}
@@ -986,8 +987,13 @@ public:
- (void)offsetCenterCoordinateBy:(NSPoint)delta animated:(BOOL)animated {
[self willChangeValueForKey:@"centerCoordinate"];
_mbglMap->cancelTransitions();
+ MGLMapCamera *oldCamera = self.camera;
_mbglMap->moveBy({ delta.x, delta.y },
MGLDurationInSecondsFromTimeInterval(animated ? MGLAnimationDuration : 0));
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
+ }
[self didChangeValueForKey:@"centerCoordinate"];
}
@@ -1028,14 +1034,34 @@ public:
}
- (void)zoomBy:(double)zoomDelta animated:(BOOL)animated {
- [self setZoomLevel:self.zoomLevel + zoomDelta animated:animated];
+ [self setZoomLevel:round(self.zoomLevel) + zoomDelta animated:animated];
+}
+
+- (void)zoomBy:(double)zoomDelta atPoint:(NSPoint)point animated:(BOOL)animated {
+ [self willChangeValueForKey:@"centerCoordinate"];
+ [self willChangeValueForKey:@"zoomLevel"];
+ double newZoom = round(self.zoomLevel) + zoomDelta;
+ MGLMapCamera *oldCamera = self.camera;
+ mbgl::ScreenCoordinate center(point.x, self.bounds.size.height - point.y);
+ _mbglMap->setZoom(newZoom, center, MGLDurationInSecondsFromTimeInterval(animated ? MGLAnimationDuration : 0));
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
+ }
+ [self didChangeValueForKey:@"zoomLevel"];
+ [self didChangeValueForKey:@"centerCoordinate"];
}
- (void)scaleBy:(double)scaleFactor atPoint:(NSPoint)point animated:(BOOL)animated {
[self willChangeValueForKey:@"centerCoordinate"];
[self willChangeValueForKey:@"zoomLevel"];
+ MGLMapCamera *oldCamera = self.camera;
mbgl::ScreenCoordinate center(point.x, self.bounds.size.height - point.y);
_mbglMap->scaleBy(scaleFactor, center, MGLDurationInSecondsFromTimeInterval(animated ? MGLAnimationDuration : 0));
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
+ }
[self didChangeValueForKey:@"zoomLevel"];
[self didChangeValueForKey:@"centerCoordinate"];
}
@@ -1118,12 +1144,6 @@ public:
}
- (void)setCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration animationTimingFunction:(nullable CAMediaTimingFunction *)function completionHandler:(nullable void (^)(void))completion {
- _mbglMap->cancelTransitions();
- if ([self.camera isEqual:camera]) {
- return;
- }
-
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera];
mbgl::AnimationOptions animationOptions;
if (duration > 0) {
animationOptions.duration.emplace(MGLDurationInSecondsFromTimeInterval(duration));
@@ -1139,8 +1159,19 @@ public:
});
};
}
+
+ if ([self.camera isEqualToMapCamera:camera]) {
+ if (completion) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completion();
+ });
+ }
+ return;
+ }
[self willChangeValueForKey:@"camera"];
+ _mbglMap->cancelTransitions();
+ mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera];
_mbglMap->easeTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
@@ -1154,12 +1185,6 @@ public:
}
- (void)flyToCamera:(MGLMapCamera *)camera withDuration:(NSTimeInterval)duration peakAltitude:(CLLocationDistance)peakAltitude completionHandler:(nullable void (^)(void))completion {
- _mbglMap->cancelTransitions();
- if ([self.camera isEqual:camera]) {
- return;
- }
-
- mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera];
mbgl::AnimationOptions animationOptions;
if (duration >= 0) {
animationOptions.duration = MGLDurationInSecondsFromTimeInterval(duration);
@@ -1180,8 +1205,19 @@ public:
});
};
}
+
+ if ([self.camera isEqualToMapCamera:camera]) {
+ if (completion) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+ completion();
+ });
+ }
+ return;
+ }
[self willChangeValueForKey:@"camera"];
+ _mbglMap->cancelTransitions();
+ mbgl::CameraOptions cameraOptions = [self cameraOptionsObjectForAnimatingToCamera:camera];
_mbglMap->flyTo(cameraOptions, animationOptions);
[self didChangeValueForKey:@"camera"];
}
@@ -1230,6 +1266,11 @@ public:
if (animated) {
animationOptions.duration = MGLDurationInSecondsFromTimeInterval(MGLAnimationDuration);
}
+
+ MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
+ if ([self.camera isEqualToMapCamera:camera]) {
+ return;
+ }
[self willChangeValueForKey:@"visibleCoordinateBounds"];
animationOptions.transitionFinishFn = ^() {
@@ -1252,7 +1293,7 @@ public:
- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions {
CLLocationCoordinate2D centerCoordinate = MGLLocationCoordinate2DFromLatLng(cameraOptions.center ? *cameraOptions.center : _mbglMap->getLatLng());
double zoomLevel = cameraOptions.zoom ? *cameraOptions.zoom : self.zoomLevel;
- CLLocationDirection direction = cameraOptions.angle ? -MGLDegreesFromRadians(*cameraOptions.angle) : self.direction;
+ CLLocationDirection direction = cameraOptions.angle ? mbgl::util::wrap(-MGLDegreesFromRadians(*cameraOptions.angle), 0., 360.) : self.direction;
CGFloat pitch = cameraOptions.pitch ? MGLDegreesFromRadians(*cameraOptions.pitch) : _mbglMap->getPitch();
CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoomLevel, pitch,
centerCoordinate.latitude,
@@ -1342,7 +1383,7 @@ public:
// the illusion that it has stayed in place during the entire gesture.
CGPoint cursorPoint = [self convertPoint:startPoint toView:nil];
cursorPoint = [self.window convertRectToScreen:{ startPoint, NSZeroSize }].origin;
- cursorPoint.y = [NSScreen mainScreen].frame.size.height - cursorPoint.y;
+ cursorPoint.y = self.window.screen.frame.size.height - cursorPoint.y;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cursorPoint);
CGDisplayShowCursor(kCGDirectMainDisplay);
}
@@ -1370,15 +1411,25 @@ public:
_directionAtBeginningOfGesture = self.direction;
_pitchAtBeginningOfGesture = _mbglMap->getPitch();
} else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
+ MGLMapCamera *oldCamera = self.camera;
+ BOOL didChangeCamera = NO;
mbgl::ScreenCoordinate center(startPoint.x, self.bounds.size.height - startPoint.y);
if (self.rotateEnabled) {
CLLocationDirection newDirection = _directionAtBeginningOfGesture - delta.x / 10;
[self willChangeValueForKey:@"direction"];
_mbglMap->setBearing(newDirection, center);
+ didChangeCamera = YES;
[self didChangeValueForKey:@"direction"];
}
if (self.pitchEnabled) {
_mbglMap->setPitch(_pitchAtBeginningOfGesture + delta.y / 5, center);
+ didChangeCamera = YES;
+ }
+
+ if (didChangeCamera
+ && [self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
}
}
} else if (self.scrollEnabled) {
@@ -1418,7 +1469,12 @@ public:
if (gestureRecognizer.magnification > -1) {
[self willChangeValueForKey:@"zoomLevel"];
[self willChangeValueForKey:@"centerCoordinate"];
+ MGLMapCamera *oldCamera = self.camera;
_mbglMap->setScale(_scaleAtBeginningOfGesture * (1 + gestureRecognizer.magnification), center);
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
+ }
[self didChangeValueForKey:@"centerCoordinate"];
[self didChangeValueForKey:@"zoomLevel"];
}
@@ -1466,7 +1522,7 @@ public:
_mbglMap->cancelTransitions();
NSPoint gesturePoint = [gestureRecognizer locationInView:self];
- [self scaleBy:2 atPoint:gesturePoint animated:YES];
+ [self zoomBy:1 atPoint:gesturePoint animated:YES];
}
- (void)smartMagnifyWithEvent:(NSEvent *)event {
@@ -1478,7 +1534,7 @@ public:
// Tap with two fingers (“right-click”) to zoom out on mice but not trackpads.
NSPoint gesturePoint = [self convertPoint:event.locationInWindow fromView:nil];
- [self scaleBy:0.5 atPoint:gesturePoint animated:YES];
+ [self zoomBy:-1 atPoint:gesturePoint animated:YES];
}
/// Rotate fingers to rotate.
@@ -1493,9 +1549,16 @@ public:
_mbglMap->setGestureInProgress(true);
_directionAtBeginningOfGesture = self.direction;
} else if (gestureRecognizer.state == NSGestureRecognizerStateChanged) {
+ MGLMapCamera *oldCamera = self.camera;
+
NSPoint rotationPoint = [gestureRecognizer locationInView:self];
mbgl::ScreenCoordinate center(rotationPoint.x, self.bounds.size.height - rotationPoint.y);
_mbglMap->setBearing(_directionAtBeginningOfGesture + gestureRecognizer.rotationInDegrees, center);
+
+ if ([self.delegate respondsToSelector:@selector(mapView:shouldChangeFromCamera:toCamera:)]
+ && ![self.delegate mapView:self shouldChangeFromCamera:oldCamera toCamera:self.camera]) {
+ self.camera = oldCamera;
+ }
} else if (gestureRecognizer.state == NSGestureRecognizerStateEnded
|| gestureRecognizer.state == NSGestureRecognizerStateCancelled) {
_mbglMap->setGestureInProgress(false);
@@ -1577,13 +1640,40 @@ public:
#pragma mark Keyboard events
- (void)keyDown:(NSEvent *)event {
- if (event.modifierFlags & NSNumericPadKeyMask) {
- // This is the recommended way to handle arrow key presses, causing
- // methods like -moveUp: and -moveToBeginningOfParagraph: to be called
- // for various standard keybindings.
- [self interpretKeyEvents:@[event]];
- } else {
- [super keyDown:event];
+ // This is the recommended way to handle arrow key presses, causing
+ // methods like -moveUp: and -moveToBeginningOfParagraph: to be called
+ // for various standard keybindings.
+ [self interpretKeyEvents:@[event]];
+}
+
+// The following action methods are declared in NSResponder.h.
+
+- (void)insertTab:(id)sender {
+ if (self.window.firstResponder == self) {
+ [self.window selectNextKeyView:self];
+ }
+}
+
+- (void)insertBacktab:(id)sender {
+ if (self.window.firstResponder == self) {
+ [self.window selectPreviousKeyView:self];
+ }
+}
+
+- (void)insertText:(NSString *)insertString {
+ switch (insertString.length == 1 ? [insertString characterAtIndex:0] : 0) {
+ case '-':
+ [self moveToEndOfParagraph:nil];
+ break;
+
+ case '+':
+ case '=':
+ [self moveToBeginningOfParagraph:nil];
+ break;
+
+ default:
+ [super insertText:insertString];
+ break;
}
}
@@ -1704,12 +1794,12 @@ public:
{
return nil;
}
-
+
std::vector<MGLAnnotationTag> annotationTags = [self annotationTagsInRect:rect];
if (annotationTags.size())
{
NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:annotationTags.size()];
-
+
for (auto const& annotationTag: annotationTags)
{
if (!_annotationContextsByAnnotationTag.count(annotationTag))
@@ -1719,10 +1809,10 @@ public:
MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag);
[annotations addObject:annotationContext.annotation];
}
-
+
return [annotations copy];
}
-
+
return nil;
}
@@ -1827,7 +1917,7 @@ public:
}
// Opt into potentially expensive tooltip tracking areas.
- if (annotation.toolTip.length) {
+ if ([annotation respondsToSelector:@selector(toolTip)] && annotation.toolTip.length) {
_wantsToolTipRects = YES;
}
}
@@ -2362,7 +2452,7 @@ public:
for (MGLAnnotationTag annotationTag : annotationTags) {
MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag];
id <MGLAnnotation> annotation = [self annotationWithTag:annotationTag];
- if (annotation.toolTip.length) {
+ if ([annotation respondsToSelector:@selector(toolTip)] && annotation.toolTip.length) {
// Add a tooltip tracking area over the annotation image’s
// frame, accounting for the image’s alignment rect.
NSImage *image = annotationImage.image;
diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h
index 1cf86263f3..08a9f7eff4 100644
--- a/platform/macos/src/MGLMapViewDelegate.h
+++ b/platform/macos/src/MGLMapViewDelegate.h
@@ -26,10 +26,10 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view is about to
change.
-
+
This method is called whenever the currently displayed map camera will start
changing for any reason.
-
+
@param mapView The map view whose viewpoint will change.
@param animated Whether the change will cause an animated effect on the map.
*/
@@ -37,14 +37,14 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view is changing.
-
+
This method is called as the currently displayed map camera changes as part of
an animation, whether due to a user gesture or due to a call to a method such
as `-[MGLMapView setCamera:animated:]`. During the animation, this method may
be called many times to report updates to the viewpoint. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view whose viewpoint is changing.
*/
- (void)mapViewCameraIsChanging:(MGLMapView *)mapView;
@@ -52,33 +52,55 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the viewpoint depicted by the map view has finished
changing.
-
+
This method is called whenever the currently displayed map camera has finished
changing, after any calls to `-mapViewRegionIsChanging:` due to animation.
-
+
@param mapView The map view whose viewpoint has changed.
@param animated Whether the change caused an animated effect on the map.
*/
- (void)mapView:(MGLMapView *)mapView cameraDidChangeAnimated:(BOOL)animated;
+/**
+ Asks the delegate whether the map view should be allowed to change from the
+ existing camera to the new camera in response to a user gesture.
+
+ This method is called as soon as the user gesture is recognized. It is not
+ called in response to a programmatic camera change, such as by setting the
+ `centerCoordinate` property or calling `-flyToCamera:completionHandler:`.
+
+ This method is called many times during gesturing, so you should avoid performing
+ complex or performance-intensive tasks in your implementation.
+
+ @param mapView The map view that the user is manipulating.
+ @param oldCamera The camera representing the viewpoint at the moment the
+ gesture is recognized. If this method returns `NO`, the map view’s camera
+ continues to be this camera.
+ @param newCamera The expected camera after the gesture completes. If this
+ method returns `YES`, this camera becomes the map view’s camera.
+ @return A Boolean value indicating whether the map view should stay at
+ `oldCamera` or change to `newCamera`.
+ */
+- (BOOL)mapView:(MGLMapView *)mapView shouldChangeFromCamera:(MGLMapCamera *)oldCamera toCamera:(MGLMapCamera *)newCamera;
+
#pragma mark Loading the Map
/**
Tells the delegate that the map view will begin to load.
-
+
This method is called whenever the map view starts loading, including when a
new style has been set and the map must reload.
-
+
@param mapView The map view that is starting to load.
*/
- (void)mapViewWillStartLoadingMap:(MGLMapView *)mapView;
/**
Tells the delegate that the map view has finished loading.
-
+
This method is called whenever the map view finishes loading, either after the
initial load or after a style change has forced a reload.
-
+
@param mapView The map view that has finished loading.
*/
- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView;
@@ -86,11 +108,11 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view was unable to load data needed for
displaying the map.
-
+
This method may be called for a variety of reasons, including a network
connection failure or a failure to fetch the style from the server. You can use
the given error message to notify the user that map data is unavailable.
-
+
@param mapView The map view that is unable to load the data.
@param error The reason the data could not be loaded.
*/
@@ -101,26 +123,26 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that the map view is about to redraw.
-
+
This method is called any time the map view needs to redraw due to a change in
the viewpoint or style property transition. This method may be called very
frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view that is about to redraw.
*/
- (void)mapViewWillStartRenderingFrame:(MGLMapView *)mapView;
/**
Tells the delegate that the map view has just redrawn.
-
+
This method is called any time the map view needs to redraw due to a change in
the viewpoint or style property transition. This method may be called very
frequently, even moreso than `-mapViewRegionIsChanging:`. Therefore, your
implementation of this method should be as lightweight as possible to avoid
affecting performance.
-
+
@param mapView The map view that has just redrawn.
*/
- (void)mapViewDidFinishRenderingFrame:(MGLMapView *)mapView fullyRendered:(BOOL)fullyRendered;
@@ -147,7 +169,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns an annotation image object to mark the given point annotation object on
the map.
-
+
@param mapView The map view that requested the annotation image.
@param annotation The object representing the annotation that is about to be
displayed.
@@ -161,7 +183,7 @@ NS_ASSUME_NONNULL_BEGIN
A value of 0.0 results in a completely transparent shape. A value of 1.0, the
default, results in a completely opaque shape.
-
+
This method sets the opacity of an entire shape, inclusive of its stroke and
fill. To independently set the values for stroke or fill, specify an alpha
component in the color returned by `-mapView:strokeColorForShapeAnnotation:` or
@@ -175,13 +197,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the color to use when rendering the outline of a shape annotation.
-
+
The default stroke color is the selected menu item color. If a pattern color is
specified, the result is undefined.
-
+
Opacity may be set by specifying an alpha component. The default alpha value is
`1.0` and results in a completely opaque stroke.
-
+
@param mapView The map view rendering the shape annotation.
@param annotation The annotation being rendered.
@return A color to use for the shape outline.
@@ -190,13 +212,13 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the color to use when rendering the fill of a polygon annotation.
-
+
The default fill color is the selected menu item color. If a pattern color is
specified, the result is undefined.
-
+
Opacity may be set by specifying an alpha component. The default alpha value is
`1.0` and results in a completely opaque shape.
-
+
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
@return The polygon’s interior fill color.
@@ -206,9 +228,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the line width in points to use when rendering the outline of a
polyline annotation.
-
+
By default, the polyline is outlined with a line 3.0 points wide.
-
+
@param mapView The map view rendering the polygon annotation.
@param annotation The annotation being rendered.
@return A line width for the polyline, measured in points.
@@ -219,9 +241,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotations has been selected.
-
+
You can use this method to track changes to the selection state of annotations.
-
+
@param mapView The map view containing the annotation.
@param annotation The annotation that was selected.
*/
@@ -229,9 +251,9 @@ NS_ASSUME_NONNULL_BEGIN
/**
Tells the delegate that one of its annotations has been deselected.
-
+
You can use this method to track changes in the selection state of annotations.
-
+
@param mapView The map view containing the annotation.
@param annotation The annotation that was deselected.
*/
@@ -242,19 +264,19 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a Boolean value indicating whether the annotation is able to display
extra information in a callout popover.
-
+
This method is called after an annotation is selected, before any callout is
displayed for the annotation.
-
+
If the return value is `YES`, a callout popover is shown when the user clicks
on an annotation, selecting it. The default callout displays the annotation’s
title and subtitle. You can customize the popover’s contents by implementing
the `-mapView:calloutViewControllerForAnnotation:` method.
-
+
If the return value is `NO`, or if this method is absent from the delegate, or
if the annotation lacks a title, the annotation will not show a callout even
when selected.
-
+
@param mapView The map view that has selected the annotation.
@param annotation The object representing the annotation.
@return A Boolean value indicating whether the annotation should show a
@@ -264,16 +286,16 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns a view controller to manage the callout popover’s content view.
-
+
Like any instance of `NSPopover`, an annotation callout manages its contents
with a view controller. The annotation object is the view controller’s
represented object. This means that you can bind controls in the view
controller’s content view to KVO-compliant properties of the annotation object,
such as `title` and `subtitle`.
-
+
If each annotation should have an identical callout, you can set the
`MGLMapView.calloutViewController` property instead.
-
+
@param mapView The map view that is requesting a callout view controller.
@param annotation The object representing the annotation.
@return A view controller for the given annotation.
diff --git a/platform/macos/src/MGLOpenGLLayer.mm b/platform/macos/src/MGLOpenGLLayer.mm
index 296e30179b..fde2b52404 100644
--- a/platform/macos/src/MGLOpenGLLayer.mm
+++ b/platform/macos/src/MGLOpenGLLayer.mm
@@ -2,15 +2,17 @@
#import "MGLMapView_Private.h"
-@implementation MGLOpenGLLayer
+@implementation MGLOpenGLLayer {
+ NSOpenGLContext *_context;
+}
- (MGLMapView *)mapView {
return (MGLMapView *)super.view;
}
-//- (BOOL)isAsynchronous {
+// - (BOOL)isAsynchronous {
// return YES;
-//}
+// }
- (BOOL)needsDisplayOnBoundsChange {
return YES;
@@ -20,8 +22,16 @@
return self.view.bounds;
}
+- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat {
+ if (!_context) {
+ _context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
+ }
+ return _context;
+}
+
- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask {
NSOpenGLPixelFormatAttribute pfas[] = {
+ NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy,
NSOpenGLPFAAccelerated,
NSOpenGLPFAClosestPolicy,
NSOpenGLPFAAccumSize, 32,
@@ -30,6 +40,7 @@
NSOpenGLPFADepthSize, 16,
NSOpenGLPFAStencilSize, 8,
NSOpenGLPFAScreenMask, mask,
+ NSOpenGLPFAAllowOfflineRenderers, // Allows using the integrated GPU
0
};
return [[NSOpenGLPixelFormat alloc] initWithAttributes:pfas];
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index 80fa1cfe31..6f1bdd22bf 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -14,6 +14,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLClockDirectionFormatter.h"
#import "MGLCompassDirectionFormatter.h"
#import "MGLCoordinateFormatter.h"
+#import "MGLDistanceFormatter.h"
#import "MGLFeature.h"
#import "MGLGeometry.h"
#import "MGLMapCamera.h"
diff --git a/platform/macos/src/NSColor+MGLAdditions.mm b/platform/macos/src/NSColor+MGLAdditions.mm
index 2a55af5cad..5288f2bc61 100644
--- a/platform/macos/src/NSColor+MGLAdditions.mm
+++ b/platform/macos/src/NSColor+MGLAdditions.mm
@@ -5,9 +5,9 @@
- (mbgl::Color)mgl_color
{
CGFloat r, g, b, a;
-
+
[[self colorUsingColorSpaceName:NSCalibratedRGBColorSpace] getRed:&r green:&g blue:&b alpha:&a];
-
+
return { (float)r, (float)g, (float)b, (float)a };
}
diff --git a/platform/macos/src/NSImage+MGLAdditions.h b/platform/macos/src/NSImage+MGLAdditions.h
index ee01a763a3..c6a80e372d 100644
--- a/platform/macos/src/NSImage+MGLAdditions.h
+++ b/platform/macos/src/NSImage+MGLAdditions.h
@@ -6,6 +6,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface NSImage (MGLAdditions)
+- (nullable instancetype)initWithMGLPremultipliedImage:(mbgl::PremultipliedImage&&)image;
+
- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage;
- (std::unique_ptr<mbgl::SpriteImage>)mgl_spriteImage;
diff --git a/platform/macos/src/NSImage+MGLAdditions.mm b/platform/macos/src/NSImage+MGLAdditions.mm
index 9c30d3c37b..397e291431 100644
--- a/platform/macos/src/NSImage+MGLAdditions.mm
+++ b/platform/macos/src/NSImage+MGLAdditions.mm
@@ -1,11 +1,28 @@
#import "NSImage+MGLAdditions.h"
+#include <mbgl/util/image+MGLAdditions.hpp>
+
@implementation NSImage (MGLAdditions)
+- (nullable instancetype)initWithMGLPremultipliedImage:(mbgl::PremultipliedImage&&)src {
+ CGImageRef image = CGImageFromMGLPremultipliedImage(std::move(src));
+ if (!image) {
+ return nil;
+ }
+
+ self = [self initWithCGImage:image size:NSZeroSize];
+ CGImageRelease(image);
+ return self;
+}
+
- (nullable instancetype)initWithMGLSpriteImage:(const mbgl::SpriteImage *)spriteImage {
- std::string png = encodePNG(spriteImage->image);
- NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
- NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:data];
+ CGImageRef image = CGImageFromMGLPremultipliedImage(spriteImage->image.clone());
+ if (!image) {
+ return nil;
+ }
+
+ NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:image];
+ CGImageRelease(image);
if (self = [self initWithSize:NSMakeSize(spriteImage->getWidth(), spriteImage->getHeight())]) {
[self addRepresentation:rep];
[self setTemplate:spriteImage->sdf];
diff --git a/platform/macos/test/MGLAttributionButtonTests.m b/platform/macos/test/MGLAttributionButtonTests.m
index f5c0aac856..b41de95317 100644
--- a/platform/macos/test/MGLAttributionButtonTests.m
+++ b/platform/macos/test/MGLAttributionButtonTests.m
@@ -16,12 +16,12 @@
}];
MGLAttributionInfo *info = [[MGLAttributionInfo alloc] initWithTitle:title URL:nil];
MGLAttributionButton *button = [[MGLAttributionButton alloc] initWithAttributionInfo:info];
-
+
NSRange symbolUnderlineRange;
NSNumber *symbolUnderline = [button.attributedTitle attribute:NSUnderlineStyleAttributeName atIndex:0 effectiveRange:&symbolUnderlineRange];
XCTAssertNil(symbolUnderline);
XCTAssertEqual(symbolUnderlineRange.length, 6);
-
+
NSRange wordUnderlineRange;
NSNumber *wordUnderline = [button.attributedTitle attribute:NSUnderlineStyleAttributeName atIndex:6 effectiveRange:&wordUnderlineRange];
XCTAssertEqualObjects(wordUnderline, @(NSUnderlineStyleSingle));
diff --git a/platform/node/bitrise.yml b/platform/node/bitrise.yml
index 0323f944a3..20dcfb1908 100644
--- a/platform/node/bitrise.yml
+++ b/platform/node/bitrise.yml
@@ -46,7 +46,7 @@ workflows:
brew install cmake
brew unlink node
brew install awscli node@4
- brew link node@4
+ brew link node@4 --force
gem install xcpretty --no-rdoc --no-ri
make node
- script:
diff --git a/platform/node/index.js b/platform/node/index.js
index 8c59023847..54ba5c0dc6 100644
--- a/platform/node/index.js
+++ b/platform/node/index.js
@@ -2,7 +2,7 @@
// Shim to wrap req.respond while preserving callback-passing API
-var mbgl = require('../../lib/mapbox-gl-native.node');
+var mbgl = require('../../lib/mapbox_gl_native.node');
var constructor = mbgl.Map.prototype.constructor;
var Map = function(options) {
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index ea3517f2a6..66cdb3eda7 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -365,7 +365,7 @@ void NodeMap::startRender(NodeMap::RenderOptions options) {
const mbgl::Size fbSize{ static_cast<uint32_t>(options.width * pixelRatio),
static_cast<uint32_t>(options.height * pixelRatio) };
- if (!view || view->size != fbSize) {
+ if (!view || view->getSize() != fbSize) {
view.reset();
view = std::make_unique<mbgl::OffscreenView>(backend.getContext(), fbSize);
}
@@ -582,18 +582,18 @@ void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
nodeMap->map->removeLayer(*Nan::Utf8String(info[0]));
}
-
+
void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
-
+
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
-
+
if (info.Length() != 3) {
return Nan::ThrowTypeError("Three arguments required");
}
-
+
if (!info[0]->IsString()) {
return Nan::ThrowTypeError("First argument must be a string");
}
@@ -601,61 +601,61 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
if (!info[1]->IsObject()) {
return Nan::ThrowTypeError("Second argument must be an object");
}
-
+
if (!info[2]->IsObject()) {
return Nan::ThrowTypeError("Third argument must be an object");
}
-
+
auto optionObject = Nan::To<v8::Object>(info[2]).ToLocalChecked();
-
+
if (!Nan::Get(optionObject, Nan::New("height").ToLocalChecked()).ToLocalChecked()->IsUint32()) {
return Nan::ThrowTypeError("height parameter required");
}
-
+
if (!Nan::Get(optionObject, Nan::New("width").ToLocalChecked()).ToLocalChecked()->IsUint32()) {
return Nan::ThrowTypeError("width parameter required");
}
-
+
if (!Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->IsUint32()) {
return Nan::ThrowTypeError("pixelRatio parameter required");
}
-
+
uint32_t imageHeight = Nan::Get(optionObject, Nan::New("height").ToLocalChecked()).ToLocalChecked()->Uint32Value();
uint32_t imageWidth = Nan::Get(optionObject, Nan::New("width").ToLocalChecked()).ToLocalChecked()->Uint32Value();
-
+
if (imageWidth > 1024 || imageHeight > 1024) {
return Nan::ThrowTypeError("Max height and width is 1024");
}
-
+
uint32_t pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->Uint32Value();
auto imageBuffer = Nan::To<v8::Object>(info[1]).ToLocalChecked()->ToObject();
-
+
if (node::Buffer::Length(imageBuffer) != imageHeight * imageWidth * 4) {
return Nan::ThrowTypeError("Image size does not match buffer size");
}
-
+
std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(node::Buffer::Length(imageBuffer));
std::copy(node::Buffer::Data(imageBuffer), node::Buffer::Data(imageBuffer) + node::Buffer::Length(imageBuffer), data.get());
mbgl::PremultipliedImage cPremultipliedImage({ imageWidth, imageHeight}, std::move(data));
nodeMap->map->addImage(*Nan::Utf8String(info[0]), std::make_unique<mbgl::SpriteImage>(std::move(cPremultipliedImage), pixelRatio));
}
-
+
void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
-
+
auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
-
+
if (info.Length() != 1) {
return Nan::ThrowTypeError("One argument required");
}
-
+
if (!info[0]->IsString()) {
return Nan::ThrowTypeError("First argument must be a string");
}
-
+
nodeMap->map->removeImage(*Nan::Utf8String(info[0]));
}
diff --git a/platform/node/test/js/require.js b/platform/node/test/js/require.js
index 1528002c20..073ca742ad 100644
--- a/platform/node/test/js/require.js
+++ b/platform/node/test/js/require.js
@@ -1 +1 @@
-var mbgl = require('../../../../lib/mapbox-gl-native');
+var mbgl = require('../../../../lib/mapbox_gl_native');
diff --git a/platform/node/test/memory.test.js b/platform/node/test/memory.test.js
index ad54098832..e23cb60f89 100644
--- a/platform/node/test/memory.test.js
+++ b/platform/node/test/memory.test.js
@@ -27,7 +27,7 @@ var tile_raster = readFixture('raster.tile');
var tile_vector = readFixture('vector.tile');
test('Memory', function(t) {
- // Trigger garbage collection before starting test, then initialize
+ // Trigger garbage collection before starting test, then initialize
// heap size
if (typeof gc === 'function') gc();
var lastHeapSize = process.memoryUsage()['heapUsed'];
@@ -86,7 +86,7 @@ test('Memory', function(t) {
if (renderCount % (testParams.numRenderings / 10) == 0) {
// Manually trigger garbage collection
if (typeof gc === 'function') gc();
-
+
var currentHeapSize = process.memoryUsage()['heapUsed'];
// Print some progress, so slow build bots don't timeout.
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index 0b453406f3..e29e62f157 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -203,6 +203,85 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
m_map->setLayoutProperty("road-label-small", "text-size", 30.0);
}
break;
+ case Qt::Key_1: {
+ if (m_symbolAnnotationId.isNull()) {
+ QMapbox::Coordinate coordinate = m_map->coordinate();
+ QMapbox::SymbolAnnotation symbol { coordinate, "default_marker" };
+ m_map->addAnnotationIcon("default_marker", QImage(":default_marker.svg"));
+ m_symbolAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::SymbolAnnotation>(symbol));
+ } else {
+ m_map->removeAnnotation(m_symbolAnnotationId.toUInt());
+ m_symbolAnnotationId.clear();
+ }
+ }
+ break;
+ case Qt::Key_2: {
+ if (m_lineAnnotationId.isNull()) {
+ QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 });
+ QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) });
+ QMapbox::CoordinatesCollections geometry { { { topLeft, bottomRight } } };
+ QMapbox::LineAnnotation line { { QMapbox::ShapeAnnotationGeometry::LineStringType, geometry }, 0.5f, 1.0f, Qt::red };
+ m_lineAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::LineAnnotation>(line));
+ } else {
+ m_map->removeAnnotation(m_lineAnnotationId.toUInt());
+ m_lineAnnotationId.clear();
+ }
+ }
+ break;
+ case Qt::Key_3: {
+ if (m_fillAnnotationId.isNull()) {
+ QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 });
+ QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) });
+ QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 });
+ QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) });
+ QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
+ QMapbox::FillAnnotation fill { { QMapbox::ShapeAnnotationGeometry::PolygonType, geometry }, 0.5f, Qt::green, QVariant::fromValue<QColor>(QColor(Qt::black)) };
+ m_fillAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::FillAnnotation>(fill));
+ } else {
+ m_map->removeAnnotation(m_fillAnnotationId.toUInt());
+ m_fillAnnotationId.clear();
+ }
+ }
+ break;
+ case Qt::Key_4: {
+ if (m_styleSourcedAnnotationId.isNull()) {
+ QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 });
+ QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) });
+ QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 });
+ QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) });
+ QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
+ QMapbox::StyleSourcedAnnotation styleSourced { { QMapbox::ShapeAnnotationGeometry::PolygonType, geometry }, "water" };
+ m_styleSourcedAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::StyleSourcedAnnotation>(styleSourced));
+ } else {
+ m_map->removeAnnotation(m_styleSourcedAnnotationId.toUInt());
+ m_styleSourcedAnnotationId.clear();
+ }
+ }
+ break;
+ case Qt::Key_5: {
+ if (m_map->layerExists("circleLayer")) {
+ m_map->removeLayer("circleLayer");
+ m_map->removeSource("circleSource");
+ } else {
+ QMapbox::CoordinatesCollections geometry { { { m_map->coordinate() } } };
+ QMapbox::Feature feature { QMapbox::Feature::PointType, geometry, {}, {} };
+
+ QVariantMap circleSource;
+ circleSource["type"] = "geojson";
+ circleSource["data"] = QVariant::fromValue<QMapbox::Feature>(feature);
+ m_map->addSource("circleSource", circleSource);
+
+ QVariantMap circle;
+ circle["id"] = "circleLayer";
+ circle["type"] = "circle";
+ circle["source"] = "circleSource";
+ m_map->addLayer(circle);
+
+ m_map->setPaintProperty("circleLayer", "circle-radius", 10.0);
+ m_map->setPaintProperty("circleLayer", "circle-color", QColor("black"));
+ }
+ }
+ break;
case Qt::Key_Tab:
m_map->cycleDebugOptions();
break;
diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp
index 23880902d3..6b4b7fd1cc 100644
--- a/platform/qt/app/mapwindow.hpp
+++ b/platform/qt/app/mapwindow.hpp
@@ -61,6 +61,11 @@ private:
unsigned m_animationTicks = 0;
unsigned m_frameDraws = 0;
+ QVariant m_symbolAnnotationId;
+ QVariant m_lineAnnotationId;
+ QVariant m_fillAnnotationId;
+ QVariant m_styleSourcedAnnotationId;
+
bool m_sourceAdded = false;
};
diff --git a/platform/qt/config.cmake b/platform/qt/config.cmake
index e1c454c757..e97c6b340a 100644
--- a/platform/qt/config.cmake
+++ b/platform/qt/config.cmake
@@ -1,7 +1,7 @@
include(platform/qt/qt.cmake)
mason_use(sqlite VERSION 3.14.2)
-mason_use(gtest VERSION 1.7.0${MASON_CXXABI_SUFFIX})
+mason_use(gtest VERSION 1.8.0${MASON_CXXABI_SUFFIX})
if(NOT WITH_QT_DECODERS)
mason_use(libjpeg-turbo VERSION 1.5.0)
@@ -23,8 +23,6 @@ macro(mbgl_platform_core)
PRIVATE platform/qt/include
)
- target_add_mason_package(mbgl-core PRIVATE sqlite)
-
target_link_libraries(mbgl-core
${MBGL_QT_LIBRARIES}
)
diff --git a/platform/qt/config.qdocconf b/platform/qt/config.qdocconf
index 7dbe6423eb..b8ade81bb2 100644
--- a/platform/qt/config.qdocconf
+++ b/platform/qt/config.qdocconf
@@ -4,10 +4,13 @@ include($QT_INSTALL_DOCS/global/compat.qdocconf)
include($QT_INSTALL_DOCS/global/fileextensions.qdocconf)
include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
+Cpp.ignoretokens = Q_DECL_EXPORT
+
project = QMapboxGL
description = Mapbox Qt SDK
language = Cpp
+outputdir = docs
headerdirs += include
sourcedirs += src
diff --git a/platform/qt/include/QQuickMapboxGL b/platform/qt/include/QQuickMapboxGL
new file mode 100644
index 0000000000..db109a1d3a
--- /dev/null
+++ b/platform/qt/include/QQuickMapboxGL
@@ -0,0 +1 @@
+#include "qquickmapboxgl.hpp"
diff --git a/platform/qt/include/QQuickMapboxGLMapParameter b/platform/qt/include/QQuickMapboxGLMapParameter
new file mode 100644
index 0000000000..603fb2bd51
--- /dev/null
+++ b/platform/qt/include/QQuickMapboxGLMapParameter
@@ -0,0 +1 @@
+#include "qquickmapboxglmapparameter.hpp"
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index b2e3b521d0..f2d96412a9 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -1,6 +1,7 @@
#ifndef QMAPBOX_H
#define QMAPBOX_H
+#include <QColor>
#include <QList>
#include <QPair>
#include <QVariant>
@@ -11,19 +12,65 @@
namespace QMapbox {
typedef QPair<double, double> Coordinate;
-typedef QList<Coordinate> LineString;
-
typedef QPair<Coordinate, double> CoordinateZoom;
+typedef QPair<double, double> ProjectedMeters;
+
+typedef QList<Coordinate> Coordinates;
+typedef QList<Coordinates> CoordinatesCollection;
+
+typedef QList<CoordinatesCollection> CoordinatesCollections;
+
+struct Q_DECL_EXPORT Feature {
+ enum Type {
+ PointType = 1,
+ LineStringType,
+ PolygonType
+ };
+ Type type;
+ CoordinatesCollections geometry;
+ QVariantMap properties;
+ QVariant id;
+};
-typedef quint32 AnnotationID;
-typedef QList<AnnotationID> AnnotationIDs;
+struct Q_DECL_EXPORT ShapeAnnotationGeometry {
+ enum Type {
+ LineStringType,
+ PolygonType,
+ MultiLineStringType,
+ MultiPolygonType
+ };
+ Type type;
+ CoordinatesCollections geometry;
+};
+
+struct Q_DECL_EXPORT SymbolAnnotation {
+ Coordinate geometry;
+ QString icon;
+};
-typedef QPair<Coordinate, QString> PointAnnotation;
+struct Q_DECL_EXPORT LineAnnotation {
+ ShapeAnnotationGeometry geometry;
+ float opacity = 1.0f;
+ float width = 1.0f;
+ QColor color = Qt::black;
+};
+
+struct Q_DECL_EXPORT FillAnnotation {
+ ShapeAnnotationGeometry geometry;
+ float opacity = 1.0f;
+ QColor color = Qt::black;
+ QVariant outlineColor;
+};
-// FIXME: We need to add support for custom style properties
-typedef QPair<LineString, QString> ShapeAnnotation;
+struct Q_DECL_EXPORT StyleSourcedAnnotation {
+ ShapeAnnotationGeometry geometry;
+ QString layerID;
+};
+
+typedef QVariant Annotation;
+typedef quint32 AnnotationID;
+typedef QList<AnnotationID> AnnotationIDs;
-// Reflects mbgl::NetworkStatus::Status.
enum NetworkMode {
Online, // Default
Offline,
@@ -51,10 +98,19 @@ typedef void (*CustomLayerRenderFunction)(void* context, const CustomLayerRender
typedef void (*CustomLayerDeinitializeFunction)(void* context);
Q_DECL_EXPORT void initializeGLExtensions();
-Q_DECL_EXPORT void registerTypes();
} // namespace QMapbox
Q_DECLARE_METATYPE(QMapbox::Coordinate);
+Q_DECLARE_METATYPE(QMapbox::Coordinates);
+Q_DECLARE_METATYPE(QMapbox::CoordinatesCollection);
+Q_DECLARE_METATYPE(QMapbox::CoordinatesCollections);
+Q_DECLARE_METATYPE(QMapbox::Feature);
+
+Q_DECLARE_METATYPE(QMapbox::SymbolAnnotation);
+Q_DECLARE_METATYPE(QMapbox::ShapeAnnotationGeometry);
+Q_DECLARE_METATYPE(QMapbox::LineAnnotation);
+Q_DECLARE_METATYPE(QMapbox::FillAnnotation);
+Q_DECLARE_METATYPE(QMapbox::StyleSourcedAnnotation);
#endif // QMAPBOX_H
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index be2d60608b..af7ed6275f 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -10,10 +10,6 @@
#include <QString>
#include <QStringList>
-#if QT_VERSION >= 0x050000
-#include <QOpenGLFramebufferObject>
-#endif
-
class QMapboxGLPrivate;
// This header follows the Qt coding style: https://wiki.qt.io/Qt_Coding_Style
@@ -183,11 +179,8 @@ public:
void addAnnotationIcon(const QString &name, const QImage &sprite);
- QMapbox::AnnotationID addPointAnnotation(const QMapbox::PointAnnotation &);
- QMapbox::AnnotationID addShapeAnnotation(const QMapbox::ShapeAnnotation &);
-
- void updatePointAnnotation(QMapbox::AnnotationID, const QMapbox::PointAnnotation &);
-
+ QMapbox::AnnotationID addAnnotation(const QMapbox::Annotation &);
+ void updateAnnotation(QMapbox::AnnotationID, const QMapbox::Annotation &);
void removeAnnotation(QMapbox::AnnotationID);
void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
@@ -201,6 +194,9 @@ public:
void resize(const QSize &size, const QSize &framebufferSize);
+ double metersPerPixelAtLatitude(double latitude, double zoom) const;
+ QMapbox::ProjectedMeters projectedMetersForCoordinate(const QMapbox::Coordinate &) const;
+ QMapbox::Coordinate coordinateForProjectedMeters(const QMapbox::ProjectedMeters &) const;
QPointF pixelForCoordinate(const QMapbox::Coordinate &) const;
QMapbox::Coordinate coordinateForPixel(const QPointF &) const;
@@ -211,6 +207,7 @@ public:
QMargins margins() const;
void addSource(const QString &sourceID, const QVariantMap& params);
+ bool sourceExists(const QString &sourceID);
void updateSource(const QString &sourceID, const QVariantMap& params);
void removeSource(const QString &sourceID);
@@ -224,16 +221,13 @@ public:
void* context,
char* before = NULL);
void addLayer(const QVariantMap &params);
+ bool layerExists(const QString &id);
void removeLayer(const QString &id);
void setFilter(const QString &layer, const QVariant &filter);
public slots:
-#if QT_VERSION >= 0x050000
- void render(QOpenGLFramebufferObject *fbo = NULL);
-#else
void render();
-#endif
void connectionEstablished();
signals:
diff --git a/platform/qt/src/qquickmapboxgl.hpp b/platform/qt/include/qquickmapboxgl.hpp
index 39b4395bd6..39b4395bd6 100644
--- a/platform/qt/src/qquickmapboxgl.hpp
+++ b/platform/qt/include/qquickmapboxgl.hpp
diff --git a/platform/qt/src/qquickmapboxglmapparameter.hpp b/platform/qt/include/qquickmapboxglmapparameter.hpp
index 1dca0cf55d..1dca0cf55d 100644
--- a/platform/qt/src/qquickmapboxglmapparameter.hpp
+++ b/platform/qt/include/qquickmapboxglmapparameter.hpp
diff --git a/platform/qt/qmlapp/main.cpp b/platform/qt/qmlapp/main.cpp
index 0dd8c96b7d..8606704002 100644
--- a/platform/qt/qmlapp/main.cpp
+++ b/platform/qt/qmlapp/main.cpp
@@ -1,4 +1,5 @@
-#include <QMapbox>
+#include <QQuickMapboxGL>
+#include <QQuickMapboxGLMapParameter>
#include <QGuiApplication>
#include <QIcon>
@@ -13,9 +14,8 @@ int main(int argc, char *argv[])
app.setWindowIcon(QIcon(":icon.png"));
#endif
- // Exposes the QQuickMapboxGL module so we
- // can do `import QQuickMapboxGL 1.0`.
- QMapbox::registerTypes();
+ qmlRegisterType<QQuickMapboxGL>("QQuickMapboxGL", 1, 0, "MapboxMap");
+ qmlRegisterType<QQuickMapboxGLMapParameter>("QQuickMapboxGL", 1, 0, "MapParameter");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake
index bd7c863f98..cee0d1080c 100644
--- a/platform/qt/qt.cmake
+++ b/platform/qt/qt.cmake
@@ -25,15 +25,16 @@ set(MBGL_QT_FILES
PRIVATE platform/default/mbgl/storage/offline_database.hpp
PRIVATE platform/default/mbgl/storage/offline_download.cpp
PRIVATE platform/default/mbgl/storage/offline_download.hpp
- PRIVATE platform/default/sqlite3.cpp
PRIVATE platform/default/sqlite3.hpp
# Misc
PRIVATE platform/default/logging_stderr.cpp
# Thread pool
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp
PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
- PRIVATE platform/default/mbgl/util/default_thread_pool.cpp
+ PRIVATE platform/default/mbgl/util/default_thread_pool.hpp
# Platform integration
PRIVATE platform/qt/src/async_task.cpp
@@ -45,6 +46,7 @@ set(MBGL_QT_FILES
PRIVATE platform/qt/src/image.cpp
PRIVATE platform/qt/src/run_loop.cpp
PRIVATE platform/qt/src/run_loop_impl.hpp
+ PRIVATE platform/qt/src/sqlite3.cpp
PRIVATE platform/qt/src/string_stdlib.cpp
PRIVATE platform/qt/src/timer.cpp
PRIVATE platform/qt/src/timer_impl.hpp
diff --git a/platform/qt/qt4.cmake b/platform/qt/qt4.cmake
index 45c299c8a8..d6d7d89417 100644
--- a/platform/qt/qt4.cmake
+++ b/platform/qt/qt4.cmake
@@ -5,6 +5,7 @@ set(MBGL_QT_LIBRARIES
PRIVATE Qt4::QtGui
PRIVATE Qt4::QtNetwork
PRIVATE Qt4::QtOpenGL
+ PRIVATE Qt4::QtSql
)
target_link_libraries(qmapboxgl
diff --git a/platform/qt/qt5.cmake b/platform/qt/qt5.cmake
index 47e178d132..7210a3d5f5 100644
--- a/platform/qt/qt5.cmake
+++ b/platform/qt/qt5.cmake
@@ -5,21 +5,21 @@ find_package(Qt5Network REQUIRED)
find_package(Qt5OpenGL REQUIRED)
find_package(Qt5Quick REQUIRED)
find_package(Qt5Widgets REQUIRED)
+find_package(Qt5Sql REQUIRED)
set(MBGL_QT_LIBRARIES
PRIVATE Qt5::Core
PRIVATE Qt5::Gui
- PRIVATE Qt5::Location
PRIVATE Qt5::Network
PRIVATE Qt5::OpenGL
- PRIVATE Qt5::Quick
+ PRIVATE Qt5::Sql
)
target_sources(qmapboxgl
+ PRIVATE platform/qt/include/qquickmapboxgl.hpp
+ PRIVATE platform/qt/include/qquickmapboxglmapparameter.hpp
PRIVATE platform/qt/src/qquickmapboxgl.cpp
- PRIVATE platform/qt/src/qquickmapboxgl.hpp
PRIVATE platform/qt/src/qquickmapboxglmapparameter.cpp
- PRIVATE platform/qt/src/qquickmapboxglmapparameter.hpp
PRIVATE platform/qt/src/qquickmapboxglrenderer.cpp
PRIVATE platform/qt/src/qquickmapboxglrenderer.hpp
)
@@ -31,6 +31,7 @@ target_link_libraries(qmapboxgl
PRIVATE Qt5::Location
PRIVATE Qt5::OpenGL
PRIVATE Qt5::Quick
+ PRIVATE Qt5::Sql
)
target_link_libraries(mbgl-qt
diff --git a/platform/qt/resources/common.qrc b/platform/qt/resources/common.qrc
index d02c04a3c2..4c792b057c 100644
--- a/platform/qt/resources/common.qrc
+++ b/platform/qt/resources/common.qrc
@@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/">
<file alias="icon.png">../../../common/icon.png</file>
+ <file alias="default_marker.svg">../../../platform/default/resources/default_marker.svg</file>
<file>source1.geojson</file>
<file>source2.geojson</file>
<file>label-arrow.svg</file>
diff --git a/platform/qt/src/http_file_source.cpp b/platform/qt/src/http_file_source.cpp
index 6831c040b0..573b707c27 100644
--- a/platform/qt/src/http_file_source.cpp
+++ b/platform/qt/src/http_file_source.cpp
@@ -108,4 +108,4 @@ uint32_t HTTPFileSource::maximumConcurrentRequests() {
#endif
}
-} // mbgl
+} // namespace mbgl
diff --git a/platform/qt/src/http_request.cpp b/platform/qt/src/http_request.cpp
index e19316fe2f..6141216c65 100644
--- a/platform/qt/src/http_request.cpp
+++ b/platform/qt/src/http_request.cpp
@@ -118,7 +118,7 @@ void HTTPRequest::handleNetworkReply(QNetworkReply *reply)
}
case 429:
response.error = std::make_unique<Error>(
- Error::Reason::RateLimit, "HTTP status code 429",
+ Error::Reason::RateLimit, "HTTP status code 429",
http::parseRetryHeaders(retryAfter, xRateLimitReset));
break;
default:
diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp
index 379b0cdd57..62bfde4fa8 100644
--- a/platform/qt/src/qmapbox.cpp
+++ b/platform/qt/src/qmapbox.cpp
@@ -4,11 +4,10 @@
#include <mbgl/map/change.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/util/default_styles.hpp>
+#include <mbgl/util/geometry.hpp>
#include <mbgl/util/traits.hpp>
#if QT_VERSION >= 0x050000
-#include "qquickmapboxgl.hpp"
-#include "qquickmapboxglmapparameter.hpp"
#include <QOpenGLContext>
#else
#include <QGLContext>
@@ -18,19 +17,232 @@
static_assert(mbgl::underlying_type(QMapbox::Online) == mbgl::underlying_type(mbgl::NetworkStatus::Status::Online), "error");
static_assert(mbgl::underlying_type(QMapbox::Offline) == mbgl::underlying_type(mbgl::NetworkStatus::Status::Offline), "error");
+// mbgl::FeatureType
+static_assert(mbgl::underlying_type(QMapbox::Feature::PointType) == mbgl::underlying_type(mbgl::FeatureType::Point), "error");
+static_assert(mbgl::underlying_type(QMapbox::Feature::LineStringType) == mbgl::underlying_type(mbgl::FeatureType::LineString), "error");
+static_assert(mbgl::underlying_type(QMapbox::Feature::PolygonType) == mbgl::underlying_type(mbgl::FeatureType::Polygon), "error");
+
namespace QMapbox {
+/*!
+ \namespace QMapbox
+ \inmodule Mapbox Qt SDK
+
+ Contains miscellaneous Mapbox bindings used throughout QMapboxGL.
+*/
+
+/*!
+ \typedef QMapbox::Coordinate
+
+ Alias for QPair<double, double>.
+ Representation for geographical coordinates - latitude and longitude, respectively.
+*/
+
+/*!
+ \typedef QMapbox::CoordinateZoom
+
+ Alias for QPair<Coordinate, double>.
+ Used as return value in QMapboxGL::coordinateZoomForBounds.
+*/
+
+/*!
+ \typedef QMapbox::ProjectedMeters
+
+ Alias for QPair<double, double>.
+ Representation for projected meters - northing and easting, respectively.
+*/
+
+/*!
+ \typedef QMapbox::Coordinates
+
+ Alias for QList<QMapbox::Coordinate>.
+ A list of QMapbox::Coordinate objects.
+*/
+
+/*!
+ \typedef QMapbox::CoordinatesCollection
+
+ Alias for QList<QMapbox::Coordinates>.
+ A list of QMapbox::Coordinates objects.
+*/
+
+/*!
+ \typedef QMapbox::CoordinatesCollections
+
+ Alias for QList<QMapbox::CoordinatesCollection>.
+ A list of QMapbox::CoordinatesCollection objects.
+*/
+
+/*!
+ \class QMapbox::Feature
+
+ \inmodule Mapbox Qt SDK
+
+ Represents \l {https://www.mapbox.com/help/define-features/}{map features}
+ via its \a type (PointType, LineStringType or PolygonType), \a geometry, \a
+ properties map and \a id (optional).
+*/
+
+/*!
+ \enum QMapbox::Feature::Type
+
+ This enum is used as basis for geometry disambiguation in QMapbox::Feature.
+
+ \value PointType A point geometry type. Means a single or a collection of points.
+ \value LineStringType A line string geometry type. Means a single or a collection of line strings.
+ \value PolygonType A polygon geometry type. Means a single or a collection of polygons.
+*/
+
+/*!
+ \class QMapbox::ShapeAnnotationGeometry
+
+ \inmodule Mapbox Qt SDK
+
+ Represents a shape annotation geometry.
+*/
+
+/*!
+ \enum QMapbox::ShapeAnnotationGeometry::Type
+
+ This enum is used as basis for shape annotation geometry disambiguation.
+
+ \value PolygonType A polygon geometry type.
+ \value LineStringType A line string geometry type.
+ \value MultiPolygonType A polygon geometry collection type.
+ \value MultiLineStringType A line string geometry collection type.
+*/
+
+/*!
+ \class QMapbox::SymbolAnnotation
+
+ \inmodule Mapbox Qt SDK
+
+ A symbol annotation comprises of its geometry and an icon identifier.
+*/
+
+/*!
+ \class QMapbox::LineAnnotation
+
+ \inmodule Mapbox Qt SDK
+
+ Represents a line annotation object, along with its properties.
+
+ A line annotation comprises of its geometry and line properties such as opacity, width and color.
+*/
+
+/*!
+ \class QMapbox::FillAnnotation
+
+ \inmodule Mapbox Qt SDK
+
+ Represents a fill annotation object, along with its properties.
+
+ A fill annotation comprises of its geometry and fill properties such as opacity, color and outline color.
+*/
+
+/*!
+ \class QMapbox::StyleSourcedAnnotation
+
+ \inmodule Mapbox Qt SDK
+
+ Represents a style sourced annotation object, along with its properties.
+
+ A style sourced annotation comprises of its geometry and a layer identifier.
+*/
+
+/*!
+ \typedef QMapbox::Annotation
+
+ Alias for QVariant.
+ Container that encapsulates either a symbol, a line, a fill or a style sourced annotation.
+*/
+
+/*!
+ \typedef QMapbox::AnnotationID
+
+ Alias for quint32 representing an annotation identifier.
+*/
+
+/*!
+ \typedef QMapbox::AnnotationIDs
+
+ Alias for QList<quint32> representing a container of annotation identifiers.
+*/
+
+/*!
+ \typedef QMapbox::CustomLayerDeinitializeFunction
+
+ Represents a callback to be called when destroying a custom layer.
+
+ \warning This is used for delegating the rendering of a layer to the user of
+ this API and is not officially supported. Use at your own risk.
+*/
+
+/*!
+ \typedef QMapbox::CustomLayerInitializeFunction
+
+ Represents a callback to be called when initializing a custom layer.
+
+ \warning This is used for delegating the rendering of a layer to the user of
+ this API and is not officially supported. Use at your own risk.
+*/
+
+/*!
+ \typedef QMapbox::CustomLayerRenderFunction
+
+ Represents a callback to be called on each render pass for a custom layer.
+
+ \warning This is used for delegating the rendering of a layer to the user of
+ this API and is not officially supported. Use at your own risk.
+*/
+
+/*!
+ \enum QMapbox::NetworkMode
+
+ This enum represents whether server requests can be performed via network.
+
+ \value Online Server network requests are accessible.
+ \value Offline Only requests to the local cache are accessible.
+*/
+
+/*!
+ \class QMapbox::CustomLayerRenderParameters
+ \inmodule Mapbox Qt SDK
+
+ QMapbox::CustomLayerRenderParameters provides the data passed on each render
+ pass for a custom layer.
+*/
+
+/*!
+ \fn QMapbox::NetworkMode QMapbox::networkMode()
+
+ Returns the current QMapbox::NetworkMode.
+*/
Q_DECL_EXPORT NetworkMode networkMode()
{
return static_cast<NetworkMode>(mbgl::NetworkStatus::Get());
}
+/*!
+ \fn void QMapbox::setNetworkMode(QMapbox::NetworkMode mode)
+
+ Forwards the network status \a mode to Mapbox GL Native engine.
+
+ File source requests uses the available network when \a mode is set to \a
+ Online, otherwise scoped to the local cache.
+*/
Q_DECL_EXPORT void setNetworkMode(NetworkMode mode)
{
mbgl::NetworkStatus::Set(static_cast<mbgl::NetworkStatus::Status>(mode));
}
-Q_DECL_EXPORT QList<QPair<QString, QString>>& defaultStyles()
+/*!
+ \fn QList<QPair<QString, QString> >& QMapbox::defaultStyles()
+
+ Returns a list containing a pair of string objects, representing the style
+ URL and name, respectively.
+*/
+Q_DECL_EXPORT QList<QPair<QString, QString> >& defaultStyles()
{
static QList<QPair<QString, QString>> styles;
@@ -44,6 +256,15 @@ Q_DECL_EXPORT QList<QPair<QString, QString>>& defaultStyles()
return styles;
}
+/*!
+ \fn void QMapbox::initializeGLExtensions()
+
+ Initializes the OpenGL extensions such as Vertex Array Objects (VAOs),
+ required by Mapbox GL Native engine.
+
+ Should be called only once, after an OpenGL context is available.
+ Consecutive calls are ignored.
+*/
Q_DECL_EXPORT void initializeGLExtensions()
{
mbgl::gl::InitializeExtensions([](const char* name) {
@@ -57,12 +278,4 @@ Q_DECL_EXPORT void initializeGLExtensions()
});
}
-Q_DECL_EXPORT void registerTypes()
-{
-#if QT_VERSION >= 0x050000
- qmlRegisterType<QQuickMapboxGL>("QQuickMapboxGL", 1, 0, "MapboxMap");
- qmlRegisterType<QQuickMapboxGLMapParameter>("QQuickMapboxGL", 1, 0, "MapParameter");
-#endif
-}
-
-}
+} // namespace QMapbox
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 86604a945f..55470a65e1 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -17,15 +17,17 @@
#include <mbgl/style/transition_options.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/util/color.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
#include <mbgl/util/run_loop.hpp>
+#include <mbgl/util/shared_thread_pool.hpp>
#include <mbgl/util/traits.hpp>
#if QT_VERSION >= 0x050000
#include <QGuiApplication>
#include <QWindow>
-#include <QOpenGLFramebufferObject>
#include <QOpenGLContext>
#else
#include <QCoreApplication>
@@ -85,20 +87,6 @@ QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
// Conversion helper functions.
-auto fromQMapboxGLShapeAnnotation(const ShapeAnnotation &shapeAnnotation) {
- const LineString &lineString = shapeAnnotation.first;
- const QString &styleLayer = shapeAnnotation.second;
-
- mbgl::LineString<double> mbglLineString;
- mbglLineString.reserve(lineString.size());
-
- for (const Coordinate &coordinate : lineString) {
- mbglLineString.emplace_back(mbgl::Point<double> { coordinate.first, coordinate.second });
- }
-
- return mbgl::StyleSourcedAnnotation { std::move(mbglLineString), styleLayer.toStdString() };
-}
-
auto fromQStringList(const QStringList &list)
{
std::vector<std::string> strings;
@@ -848,42 +836,72 @@ void QMapboxGL::setTransitionOptions(qint64 duration, qint64 delay) {
d_ptr->mapObj->setTransitionOptions(mbgl::style::TransitionOptions{ convert(duration), convert(delay) });
}
-mbgl::Annotation fromPointAnnotation(const PointAnnotation &pointAnnotation) {
- const Coordinate &coordinate = pointAnnotation.first;
- const QString &icon = pointAnnotation.second;
- return mbgl::SymbolAnnotation { mbgl::Point<double> { coordinate.second, coordinate.first }, icon.toStdString() };
+mbgl::Annotation asMapboxGLAnnotation(const QMapbox::Annotation & annotation) {
+ auto asMapboxGLGeometry = [](const QMapbox::ShapeAnnotationGeometry &geometry) {
+ mbgl::ShapeAnnotationGeometry result;
+ switch (geometry.type) {
+ case QMapbox::ShapeAnnotationGeometry::LineStringType:
+ result = { asMapboxGLLineString(geometry.geometry.first().first()) };
+ break;
+ case QMapbox::ShapeAnnotationGeometry::PolygonType:
+ result = { asMapboxGLPolygon(geometry.geometry.first()) };
+ break;
+ case QMapbox::ShapeAnnotationGeometry::MultiLineStringType:
+ result = { asMapboxGLMultiLineString(geometry.geometry.first()) };
+ break;
+ case QMapbox::ShapeAnnotationGeometry::MultiPolygonType:
+ result = { asMapboxGLMultiPolygon(geometry.geometry) };
+ break;
+ }
+ return result;
+ };
+
+ if (annotation.canConvert<QMapbox::SymbolAnnotation>()) {
+ QMapbox::SymbolAnnotation symbolAnnotation = annotation.value<QMapbox::SymbolAnnotation>();
+ QMapbox::Coordinate& pair = symbolAnnotation.geometry;
+ return mbgl::SymbolAnnotation { mbgl::Point<double> { pair.second, pair.first }, symbolAnnotation.icon.toStdString() };
+ } else if (annotation.canConvert<QMapbox::LineAnnotation>()) {
+ QMapbox::LineAnnotation lineAnnotation = annotation.value<QMapbox::LineAnnotation>();
+ auto color = mbgl::Color::parse(lineAnnotation.color.name().toStdString());
+ return mbgl::LineAnnotation { asMapboxGLGeometry(lineAnnotation.geometry), lineAnnotation.opacity, lineAnnotation.width, { *color } };
+ } else if (annotation.canConvert<QMapbox::FillAnnotation>()) {
+ QMapbox::FillAnnotation fillAnnotation = annotation.value<QMapbox::FillAnnotation>();
+ auto color = mbgl::Color::parse(fillAnnotation.color.name().toStdString());
+ if (fillAnnotation.outlineColor.canConvert<QColor>()) {
+ auto outlineColor = mbgl::Color::parse(fillAnnotation.outlineColor.value<QColor>().name().toStdString());
+ return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, { *outlineColor } };
+ } else {
+ return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, {} };
+ }
+ } else if (annotation.canConvert<QMapbox::StyleSourcedAnnotation>()) {
+ QMapbox::StyleSourcedAnnotation styleSourcedAnnotation = annotation.value<QMapbox::StyleSourcedAnnotation>();
+ return mbgl::StyleSourcedAnnotation { asMapboxGLGeometry(styleSourcedAnnotation.geometry), styleSourcedAnnotation.layerID.toStdString() };
+ }
+
+ qWarning() << "Unable to convert annotation:" << annotation;
+ return {};
}
/*!
- Adds a \a point annotation to the map.
+ Adds an \a annotation to the map.
Returns the unique identifier for the new annotation.
\sa addAnnotationIcon()
*/
-QMapbox::AnnotationID QMapboxGL::addPointAnnotation(const QMapbox::PointAnnotation &point)
+QMapbox::AnnotationID QMapboxGL::addAnnotation(const QMapbox::Annotation &annotation)
{
- return d_ptr->mapObj->addAnnotation(fromPointAnnotation(point));
+ return d_ptr->mapObj->addAnnotation(asMapboxGLAnnotation(annotation));
}
/*!
- Updates an existing \a point annotation referred by \a id.
+ Updates an existing \a annotation referred by \a id.
\sa addAnnotationIcon()
*/
-void QMapboxGL::updatePointAnnotation(QMapbox::AnnotationID id, const QMapbox::PointAnnotation &point)
+void QMapboxGL::updateAnnotation(QMapbox::AnnotationID id, const QMapbox::Annotation &annotation)
{
- d_ptr->mapObj->updateAnnotation(id, fromPointAnnotation(point));
-}
-
-/*!
- Adds a \a shape annotation to the map.
-
- Returns the unique identifier for the new annotation.
-*/
-QMapbox::AnnotationID QMapboxGL::addShapeAnnotation(const QMapbox::ShapeAnnotation &shape)
-{
- return d_ptr->mapObj->addAnnotation(fromQMapboxGLShapeAnnotation(shape));
+ d_ptr->mapObj->updateAnnotation(id, asMapboxGLAnnotation(annotation));
}
/*!
@@ -1087,10 +1105,10 @@ void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize)
Adds an \a icon to the annotation icon pool. This can be later used by the annotation
functions to shown any drawing on the map by referencing its \a name.
- Unlike using addIcon() for runtime styling, annotations added with addPointAnnotation()
+ Unlike using addIcon() for runtime styling, annotations added with addAnnotation()
will survive style changes.
- \sa addPointAnnotation()
+ \sa addAnnotation()
*/
void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon)
{
@@ -1100,6 +1118,32 @@ void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon)
}
/*!
+ Returns the amount of meters per pixel from a given \a latitude and \a zoom.
+*/
+double QMapboxGL::metersPerPixelAtLatitude(double latitude, double zoom) const
+{
+ return d_ptr->mapObj->getMetersPerPixelAtLatitude(latitude, zoom);
+}
+
+/*!
+ Return the projected meters for a given \a coordinate_ object.
+*/
+QMapbox::ProjectedMeters QMapboxGL::projectedMetersForCoordinate(const QMapbox::Coordinate &coordinate_) const
+{
+ auto projectedMeters = d_ptr->mapObj->projectedMetersForLatLng(mbgl::LatLng { coordinate_.first, coordinate_.second });
+ return QMapbox::ProjectedMeters(projectedMeters.northing, projectedMeters.easting);
+}
+
+/*!
+ Returns the coordinate for a given \a projectedMeters object.
+*/
+QMapbox::Coordinate QMapboxGL::coordinateForProjectedMeters(const QMapbox::ProjectedMeters &projectedMeters) const
+{
+ auto latLng = d_ptr->mapObj->latLngForProjectedMeters(mbgl::ProjectedMeters { projectedMeters.first, projectedMeters.second });
+ return QMapbox::Coordinate(latLng.latitude, latLng.longitude);
+}
+
+/*!
\fn QMapboxGL::pixelForCoordinate(const QMapbox::Coordinate &coordinate) const
Returns the offset in pixels for \a coordinate. The origin pixel coordinate is
@@ -1226,6 +1270,14 @@ void QMapboxGL::addSource(const QString &id, const QVariantMap &params)
}
/*!
+ Returns true if the layer with given \a sourceID exists, false otherwise.
+*/
+bool QMapboxGL::sourceExists(const QString& sourceID)
+{
+ return !!d_ptr->mapObj->getSource(sourceID.toStdString());
+}
+
+/*!
Updates the source \a id with new \a params.
If the source does not exist, it will be added like in addSource(). Only
@@ -1330,7 +1382,15 @@ void QMapboxGL::addLayer(const QVariantMap &params)
}
/*!
- Removes the layer \a id.
+ Returns true if the layer with given \a id exists, false otherwise.
+*/
+bool QMapboxGL::layerExists(const QString& id)
+{
+ return !!d_ptr->mapObj->getLayer(id.toStdString());
+}
+
+/*!
+ Removes the layer with given \a id.
*/
void QMapboxGL::removeLayer(const QString& id)
{
@@ -1431,17 +1491,9 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
This function should be called only after the signal needsRendering() is
emitted at least once.
*/
-#if QT_VERSION >= 0x050000
-void QMapboxGL::render(QOpenGLFramebufferObject *fbo)
-{
- d_ptr->dirty = false;
- d_ptr->fbo = fbo;
- d_ptr->mapObj->render(*d_ptr);
-}
-#else
void QMapboxGL::render()
{
-#if defined(__APPLE__)
+#if defined(__APPLE__) && QT_VERSION < 0x050000
// FIXME Qt 4.x provides an incomplete FBO at start.
// See https://bugreports.qt.io/browse/QTBUG-36802 for details.
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
@@ -1452,7 +1504,6 @@ void QMapboxGL::render()
d_ptr->dirty = false;
d_ptr->mapObj->render(*d_ptr);
}
-#endif
/*!
Informs the map that the network connection has been established, causing
@@ -1498,10 +1549,10 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
settings.cacheDatabasePath().toStdString(),
settings.assetPath().toStdString(),
settings.cacheDatabaseMaximumSize()))
- , threadPool(4)
+ , threadPool(mbgl::sharedThreadPool())
, mapObj(std::make_unique<mbgl::Map>(
*this, mbgl::Size{ static_cast<uint32_t>(size.width()), static_cast<uint32_t>(size.height()) },
- pixelRatio, *fileSourceObj, threadPool,
+ pixelRatio, *fileSourceObj, *threadPool,
mbgl::MapMode::Continuous,
static_cast<mbgl::GLContextMode>(settings.contextMode()),
static_cast<mbgl::ConstrainMode>(settings.constrainMode()),
@@ -1521,24 +1572,12 @@ QMapboxGLPrivate::~QMapboxGLPrivate()
{
}
-#if QT_VERSION >= 0x050000
-void QMapboxGLPrivate::bind() {
- if (fbo) {
- fbo->bind();
- getContext().bindFramebuffer.setDirty();
- getContext().viewport = {
- 0, 0, { static_cast<uint32_t>(fbo->width()), static_cast<uint32_t>(fbo->height()) }
- };
- }
-}
-#else
void QMapboxGLPrivate::bind() {
getContext().bindFramebuffer = 0;
getContext().viewport = {
0, 0, { static_cast<uint32_t>(fbSize.width()), static_cast<uint32_t>(fbSize.height()) }
};
}
-#endif
void QMapboxGLPrivate::invalidate()
{
diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp
index e2edf3f96c..ee7bff0872 100644
--- a/platform/qt/src/qmapboxgl_p.hpp
+++ b/platform/qt/src/qmapboxgl_p.hpp
@@ -38,15 +38,11 @@ public:
QMapboxGL *q_ptr { nullptr };
std::unique_ptr<mbgl::DefaultFileSource> fileSourceObj;
- mbgl::ThreadPool threadPool;
+ std::shared_ptr<mbgl::ThreadPool> threadPool;
std::unique_ptr<mbgl::Map> mapObj;
bool dirty { false };
-#if QT_VERSION >= 0x050000
- QOpenGLFramebufferObject *fbo { nullptr };
-#endif
-
public slots:
void connectionEstablished();
diff --git a/platform/qt/src/qquickmapboxglrenderer.cpp b/platform/qt/src/qquickmapboxglrenderer.cpp
index 69c22d35d7..133bed40e2 100644
--- a/platform/qt/src/qquickmapboxglrenderer.cpp
+++ b/platform/qt/src/qquickmapboxglrenderer.cpp
@@ -38,7 +38,9 @@ QOpenGLFramebufferObject* QQuickMapboxGLRenderer::createFramebufferObject(const
void QQuickMapboxGLRenderer::render()
{
- m_map->render(framebufferObject());
+ framebufferObject()->bind();
+ m_map->render();
+ framebufferObject()->release();
}
void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item)
diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp
index e49b6dbe3e..4b93ca7423 100644
--- a/platform/qt/src/qt_conversion.hpp
+++ b/platform/qt/src/qt_conversion.hpp
@@ -4,6 +4,8 @@
#include <mbgl/util/feature.hpp>
#include <mbgl/util/optional.hpp>
+#include <QMapbox>
+
#include <QColor>
#include <QVariant>
@@ -28,7 +30,13 @@ inline QVariant arrayMember(const QVariant& value, std::size_t i) {
}
inline bool isObject(const QVariant& value) {
- return value.canConvert(QVariant::Map) || value.type() == QVariant::ByteArray;
+ return value.canConvert(QVariant::Map)
+ || value.type() == QVariant::ByteArray
+#if QT_VERSION >= 0x050000
+ || QString(value.typeName()) == QStringLiteral("QMapbox::Feature");
+#else
+ || QString(value.typeName()) == QString("QMapbox::Feature");
+#endif
}
inline optional<QVariant> objectMember(const QVariant& value, const char* key) {
diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp
index 07813623fd..038b051941 100644
--- a/platform/qt/src/qt_geojson.hpp
+++ b/platform/qt/src/qt_geojson.hpp
@@ -4,19 +4,195 @@
#include <mbgl/style/conversion/geojson.hpp>
#include <mbgl/util/rapidjson.hpp>
+#include <QMapbox>
+
#include <QByteArray>
+#include <QDebug>
#include <QVariant>
#include <sstream>
#include <string>
+namespace QMapbox {
+
+mbgl::Point<double> asMapboxGLPoint(const QMapbox::Coordinate &coordinate) {
+ return mbgl::Point<double> { coordinate.second, coordinate.first };
+}
+
+mbgl::MultiPoint<double> asMapboxGLMultiPoint(const QMapbox::Coordinates &multiPoint) {
+ mbgl::MultiPoint<double> mbglMultiPoint;
+ mbglMultiPoint.reserve(multiPoint.size());
+ for (const auto &point: multiPoint) {
+ mbglMultiPoint.emplace_back(asMapboxGLPoint(point));
+ }
+ return mbglMultiPoint;
+};
+
+mbgl::LineString<double> asMapboxGLLineString(const QMapbox::Coordinates &lineString) {
+ mbgl::LineString<double> mbglLineString;
+ mbglLineString.reserve(lineString.size());
+ for (const auto &coordinate : lineString) {
+ mbglLineString.emplace_back(asMapboxGLPoint(coordinate));
+ }
+ return mbglLineString;
+};
+
+mbgl::MultiLineString<double> asMapboxGLMultiLineString(const QMapbox::CoordinatesCollection &multiLineString) {
+ mbgl::MultiLineString<double> mbglMultiLineString;
+ mbglMultiLineString.reserve(multiLineString.size());
+ for (const auto &lineString : multiLineString) {
+ mbglMultiLineString.emplace_back(std::forward<mbgl::LineString<double>>(asMapboxGLLineString(lineString)));
+ }
+ return mbglMultiLineString;
+};
+
+mbgl::Polygon<double> asMapboxGLPolygon(const QMapbox::CoordinatesCollection &polygon) {
+ mbgl::Polygon<double> mbglPolygon;
+ mbglPolygon.reserve(polygon.size());
+ for (const auto &linearRing : polygon) {
+ mbgl::LinearRing<double> mbglLinearRing;
+ mbglLinearRing.reserve(linearRing.size());
+ for (const auto &coordinate: linearRing) {
+ mbglLinearRing.emplace_back(asMapboxGLPoint(coordinate));
+ }
+ mbglPolygon.emplace_back(std::move(mbglLinearRing));
+ }
+ return mbglPolygon;
+};
+
+mbgl::MultiPolygon<double> asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon) {
+ mbgl::MultiPolygon<double> mbglMultiPolygon;
+ mbglMultiPolygon.reserve(multiPolygon.size());
+ for (const auto &polygon : multiPolygon) {
+ mbglMultiPolygon.emplace_back(std::forward<mbgl::Polygon<double>>(asMapboxGLPolygon(polygon)));
+ }
+ return mbglMultiPolygon;
+};
+
+mbgl::Value asMapboxGLPropertyValue(const QVariant &value) {
+ auto valueList = [](const QVariantList &list) {
+ std::vector<mbgl::Value> mbglList;
+ mbglList.reserve(list.size());
+ for (const auto& listValue : list) {
+ mbglList.emplace_back(asMapboxGLPropertyValue(listValue));
+ }
+ return mbglList;
+ };
+
+ auto valueMap = [](const QVariantMap &map) {
+ std::unordered_map<std::string, mbgl::Value> mbglMap;
+ mbglMap.reserve(map.size());
+ auto it = map.constBegin();
+ while (it != map.constEnd()) {
+ mbglMap.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value())));
+ ++it;
+ }
+ return mbglMap;
+ };
+
+ switch (value.type()) {
+#if QT_VERSION >= 0x050000
+ case QMetaType::UnknownType:
+#else
+ case QVariant::Invalid:
+#endif
+ return mbgl::NullValue {};
+ case QMetaType::Bool:
+ return { value.toBool() };
+ case QMetaType::ULongLong:
+ return { uint64_t(value.toULongLong()) };
+ case QMetaType::LongLong:
+ return { int64_t(value.toLongLong()) };
+ case QMetaType::Double:
+ return { value.toDouble() };
+ case QMetaType::QString:
+ return { value.toString().toStdString() };
+ case QMetaType::QVariantList:
+ return valueList(value.toList());
+ case QMetaType::QVariantMap:
+ return valueMap(value.toMap());
+ default:
+ qWarning() << "Unsupported feature property value:" << value;
+ return {};
+ }
+}
+
+mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) {
+ switch (id.type()) {
+#if QT_VERSION >= 0x050000
+ case QMetaType::UnknownType:
+#else
+ case QVariant::Invalid:
+#endif
+ return {};
+ case QMetaType::ULongLong:
+ return { uint64_t(id.toULongLong()) };
+ case QMetaType::LongLong:
+ return { int64_t(id.toLongLong()) };
+ case QMetaType::Double:
+ return { id.toDouble() };
+ case QMetaType::QString:
+ return { id.toString().toStdString() };
+ default:
+ qWarning() << "Unsupported feature identifier:" << id;
+ return {};
+ }
+}
+
+mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) {
+ mbgl::PropertyMap properties;
+ properties.reserve(feature.properties.size());
+ auto it = feature.properties.constBegin();
+ while (it != feature.properties.constEnd()) {
+ properties.emplace(std::make_pair(it.key().toStdString(), asMapboxGLPropertyValue(it.value())));
+ }
+
+ mbgl::FeatureIdentifier id = asMapboxGLFeatureIdentifier(feature.id);
+
+ if (feature.type == QMapbox::Feature::PointType) {
+ const QMapbox::Coordinates &points = feature.geometry.first().first();
+ if (points.size() == 1) {
+ return { asMapboxGLPoint(points.first()), std::move(properties), std::move(id) };
+ } else {
+ return { asMapboxGLMultiPoint(points), std::move(properties), std::move(id) };
+ }
+ } else if (feature.type == QMapbox::Feature::LineStringType) {
+ const QMapbox::CoordinatesCollection &lineStrings = feature.geometry.first();
+ if (lineStrings.size() == 1) {
+ return { asMapboxGLLineString(lineStrings.first()), std::move(properties), std::move(id) };
+ } else {
+ return { asMapboxGLMultiLineString(lineStrings), std::move(properties), std::move(id) };
+ }
+ } else { // PolygonType
+ const QMapbox::CoordinatesCollections &polygons = feature.geometry;
+ if (polygons.size() == 1) {
+ return { asMapboxGLPolygon(polygons.first()), std::move(properties), std::move(id) };
+ } else {
+ return { asMapboxGLMultiPolygon(polygons), std::move(properties), std::move(id) };
+ }
+ }
+};
+
+} // namespace QMapbox
+
namespace mbgl {
namespace style {
namespace conversion {
template <>
+Result<GeoJSON> convertGeoJSON(const QMapbox::Feature& feature) {
+ return Result<GeoJSON> { GeoJSON { asMapboxGLFeature(feature) } };
+}
+
+template <>
Result<GeoJSON> convertGeoJSON(const QVariant& value) {
- if (value.type() != QVariant::ByteArray) {
+#if QT_VERSION >= 0x050000
+ if (value.typeName() == QStringLiteral("QMapbox::Feature")) {
+#else
+ if (value.typeName() == QString("QMapbox::Feature")) {
+#endif
+ return convertGeoJSON(value.value<QMapbox::Feature>());
+ } else if (value.type() != QVariant::ByteArray) {
return Error { "JSON data must be in QByteArray" };
}
@@ -36,7 +212,7 @@ Result<GeoJSON> convertGeoJSON(const QVariant& value) {
return Error { message.str() };
}
- conversion::Result<GeoJSON> geoJSON = conversion::convertGeoJSON<JSValue>(d);
+ Result<GeoJSON> geoJSON = convertGeoJSON<JSValue>(d);
if (!geoJSON) {
return Error { geoJSON.error().message };
}
diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp
new file mode 100644
index 0000000000..3470c36910
--- /dev/null
+++ b/platform/qt/src/sqlite3.cpp
@@ -0,0 +1,436 @@
+#include "sqlite3.hpp"
+
+#include <QSqlDatabase>
+#include <QSqlError>
+#include <QSqlQuery>
+#include <QStringList>
+#include <QThread>
+#include <QVariant>
+
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+#include <chrono>
+
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mbgl/util/optional.hpp>
+#include <mbgl/util/string.hpp>
+#include <mbgl/util/traits.hpp>
+
+namespace mapbox {
+namespace sqlite {
+
+// https://www.sqlite.org/rescode.html#ok
+static_assert(mbgl::underlying_type(Exception::OK) == 0, "error");
+// https://www.sqlite.org/rescode.html#cantopen
+static_assert(mbgl::underlying_type(Exception::CANTOPEN) == 14, "error");
+// https://www.sqlite.org/rescode.html#notadb
+static_assert(mbgl::underlying_type(Exception::NOTADB) == 26, "error");
+
+void checkQueryError(const QSqlQuery& query) {
+ QSqlError lastError = query.lastError();
+ if (lastError.type() != QSqlError::NoError) {
+#if QT_VERSION >= 0x050300
+ throw Exception { lastError.nativeErrorCode().toInt(), lastError.text().toStdString() };
+#else
+ throw Exception { lastError.number(), lastError.text().toStdString() };
+#endif
+ }
+}
+
+void checkDatabaseError(const QSqlDatabase &db) {
+ QSqlError lastError = db.lastError();
+ if (lastError.type() != QSqlError::NoError) {
+#if QT_VERSION >= 0x050300
+ throw Exception { lastError.nativeErrorCode().toInt(), lastError.text().toStdString() };
+#else
+ throw Exception { lastError.number(), lastError.text().toStdString() };
+#endif
+ }
+}
+
+class DatabaseImpl {
+public:
+ DatabaseImpl(const char* filename, int flags) {
+ static uint64_t count = 0;
+ const QString connectionName = QString::number(uint64_t(QThread::currentThread())) + QString::number(count++);
+
+ if (!QSqlDatabase::drivers().contains("QSQLITE")) {
+ throw Exception { Exception::Code::CANTOPEN, "SQLite driver not found." };
+ }
+
+ assert(!QSqlDatabase::contains(connectionName));
+ db.reset(new QSqlDatabase(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()) {
+ checkDatabaseError(*db);
+ }
+ }
+
+ ~DatabaseImpl() {
+ db->close();
+ checkDatabaseError(*db);
+ }
+
+ QScopedPointer<QSqlDatabase> db;
+};
+
+class StatementImpl {
+public:
+ StatementImpl(const QString& sql, const QSqlDatabase& db) : query(db) {
+ query.setForwardOnly(true);
+ if (!query.prepare(sql)) {
+ checkQueryError(query);
+ }
+ }
+
+ ~StatementImpl() {
+ query.clear();
+ }
+
+ QSqlQuery query;
+ int64_t lastInsertRowId = 0;
+ int64_t changes = 0;
+};
+
+template <typename T>
+using optional = std::experimental::optional<T>;
+
+
+Database::Database(const std::string& file, int flags)
+ : impl(std::make_unique<DatabaseImpl>(file.c_str(), flags)) {
+ assert(impl);
+}
+
+Database::Database(Database &&other)
+ : impl(std::move(other.impl)) {
+ assert(impl);
+}
+
+Database &Database::operator=(Database &&other) {
+ std::swap(impl, other.impl);
+ assert(impl);
+ return *this;
+}
+
+Database::~Database() {
+}
+
+Database::operator bool() const {
+ return impl.operator bool();
+}
+
+void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
+ assert(impl);
+ std::string timeoutStr = mbgl::util::toString(timeout.count());
+ QString connectOptions = impl->db->connectOptions();
+ if (connectOptions.isEmpty()) {
+ if (!connectOptions.isEmpty()) connectOptions.append(';');
+ connectOptions.append("QSQLITE_BUSY_TIMEOUT=").append(QString::fromStdString(timeoutStr));
+ }
+ if (impl->db->isOpen()) {
+ impl->db->close();
+ }
+ impl->db->setConnectOptions(connectOptions);
+ if (!impl->db->open()) {
+ checkDatabaseError(*impl->db);
+ }
+}
+
+void Database::exec(const std::string &sql) {
+ assert(impl);
+ QStringList statements = QString::fromStdString(sql).split(';', QString::SkipEmptyParts);
+ statements.removeAll("\n");
+ for (QString statement : statements) {
+ if (!statement.endsWith(';')) {
+ statement.append(';');
+ }
+ QSqlQuery query(*impl->db);
+ query.setForwardOnly(true);
+ query.prepare(statement);
+ if (!query.exec()) {
+ checkQueryError(query);
+ }
+ }
+}
+
+Statement Database::prepare(const char *query) {
+ return Statement(this, query);
+}
+
+Statement::Statement(Database *db, const char *sql)
+ : impl(std::make_unique<StatementImpl>(QString(sql), *db->impl->db)) {
+ assert(impl);
+}
+
+Statement::Statement(Statement &&other)
+ : impl(std::move(other.impl)) {
+ assert(impl);
+}
+
+Statement &Statement::operator=(Statement &&other) {
+ assert(impl);
+ std::swap(impl, other.impl);
+ return *this;
+}
+
+Statement::~Statement() {
+}
+
+Statement::operator bool() const {
+ assert(impl);
+ return impl.operator bool();
+}
+
+template void Statement::bind(int, int64_t);
+
+template <typename T>
+void Statement::bind(int offset, T value) {
+ assert(impl);
+ // Field numbering starts at 0.
+ impl->query.bindValue(offset - 1, QVariant::fromValue<T>(value), QSql::In);
+ checkQueryError(impl->query);
+}
+
+template <>
+void Statement::bind(int offset, std::nullptr_t) {
+ assert(impl);
+ // Field numbering starts at 0.
+ impl->query.bindValue(offset - 1, QVariant(QVariant::Invalid), QSql::In);
+ checkQueryError(impl->query);
+}
+
+template <>
+void Statement::bind(int offset, int32_t value) {
+ bind(offset, static_cast<int64_t>(value));
+}
+
+template <>
+void Statement::bind(int offset, bool value) {
+ bind(offset, static_cast<int>(value));
+}
+
+template <>
+void Statement::bind(int offset, int8_t value) {
+ bind(offset, static_cast<int64_t>(value));
+}
+
+template <>
+void Statement::bind(int offset, uint8_t value) {
+ bind(offset, static_cast<int64_t>(value));
+}
+
+template <>
+void Statement::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) {
+ if (value) {
+ bind(offset, *value);
+ } else {
+ bind(offset, nullptr);
+ }
+}
+
+template <>
+void Statement::bind(int offset, optional<mbgl::Timestamp> value) {
+ if (value) {
+ bind(offset, *value);
+ } else {
+ bind(offset, nullptr);
+ }
+}
+
+void Statement::bind(int offset, const char* value, std::size_t length, bool retain) {
+ assert(impl);
+ if (length > std::numeric_limits<int>::max()) {
+ // Kept for consistence with the default implementation.
+ throw std::range_error("value too long");
+ }
+
+ // Field numbering starts at 0.
+ impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
+ QByteArray::fromRawData(value, length), QSql::In);
+
+ checkQueryError(impl->query);
+}
+
+void Statement::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) {
+ const char* value = reinterpret_cast<const char*>(value_);
+
+ // Field numbering starts at 0.
+ impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
+ QByteArray::fromRawData(value, length), QSql::In | QSql::Binary);
+
+ checkQueryError(impl->query);
+}
+
+void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+ bindBlob(offset, value.data(), value.size(), retain);
+}
+
+bool Statement::run() {
+ assert(impl);
+ if (impl->query.isValid()) {
+ return impl->query.next();
+ }
+
+ assert(!impl->query.isActive());
+ impl->query.setForwardOnly(true);
+ if (!impl->query.exec()) {
+ checkQueryError(impl->query);
+ }
+
+ impl->lastInsertRowId = impl->query.lastInsertId().value<int64_t>();
+ impl->changes = impl->query.numRowsAffected();
+
+ return impl->query.next();
+}
+
+template int Statement::get(int);
+template int64_t Statement::get(int);
+template double Statement::get(int);
+
+template <typename T> T Statement::get(int offset) {
+ assert(impl && impl->query.isValid());
+ QVariant value = impl->query.value(offset);
+ checkQueryError(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);
+ 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);
+ return std::chrono::time_point_cast<std::chrono::seconds>(
+ std::chrono::system_clock::from_time_t(value.value<std::time_t>()));
+}
+
+template <> optional<int64_t> Statement::get(int offset) {
+ assert(impl && impl->query.isValid());
+ QVariant value = impl->query.value(offset);
+ checkQueryError(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);
+ 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);
+ 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);
+ 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);
+ if (value.isNull())
+ return {};
+ return { std::chrono::time_point_cast<mbgl::Seconds>(
+ std::chrono::system_clock::from_time_t(value.value<std::time_t>())) };
+}
+
+void Statement::reset() {
+ assert(impl);
+ impl->query.finish();
+}
+
+void Statement::clearBindings() {
+ // no-op
+}
+
+int64_t Statement::lastInsertRowId() const {
+ assert(impl);
+ return impl->lastInsertRowId;
+}
+
+uint64_t Statement::changes() const {
+ assert(impl);
+ return (impl->changes < 0 ? 0 : impl->changes);
+}
+
+Transaction::Transaction(Database& db_, Mode mode)
+ : db(db_) {
+ switch (mode) {
+ case Deferred:
+ db.exec("BEGIN DEFERRED TRANSACTION");
+ break;
+ case Immediate:
+ db.exec("BEGIN IMMEDIATE TRANSACTION");
+ break;
+ case Exclusive:
+ db.exec("BEGIN EXCLUSIVE TRANSACTION");
+ break;
+ }
+}
+
+Transaction::~Transaction() {
+ if (needRollback) {
+ try {
+ rollback();
+ } catch (...) {
+ // Ignore failed rollbacks in destructor.
+ }
+ }
+}
+
+void Transaction::commit() {
+ needRollback = false;
+ db.exec("COMMIT TRANSACTION");
+}
+
+void Transaction::rollback() {
+ needRollback = false;
+ db.exec("ROLLBACK TRANSACTION");
+}
+
+} // namespace sqlite
+} // namespace mapbox
diff --git a/scripts/build-shaders.js b/scripts/build-shaders.js
deleted file mode 100755
index d00762acf0..0000000000
--- a/scripts/build-shaders.js
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env node
-
-var path = require('path');
-var fs = require('fs');
-var mkdirp = require('mkdirp');
-
-var shaderName = process.argv[2];
-var inputPath = process.argv[3];
-var outputPath = process.argv[4];
-
-if (!shaderName || !inputPath || !outputPath) {
- console.warn('Not enough arguments.');
- console.warn('Usage: %s shaderName /path-to-shader-sources /output-path', path.basename(process.argv[1]));
- process.exit(1);
-}
-
-var pragmaMapboxRe = /(\s*)#pragma\s+mapbox\s*:\s+(define|initialize)\s+(low|medium|high)p\s+(float|vec(?:2|3|4))\s+(.*)/;
-
-
-function applyPragmas(source) {
- return '\n' + source.split('\n').map(function(line) {
- var params = line.match(pragmaMapboxRe);
- if (params) {
- if (params[2] === 'define') {
- return params[1] + 'uniform ' + params[3] + 'p ' + params[4] + ' u_' + params[5] + ';';
- } else {
- return params[1] + params[3] + 'p ' + params[4] + ' ' + params[5] + ' = u_' + params[5] + ';';
- }
- } else {
- return line;
- }
- }).join('\n');
-}
-
-var vertexPrelude = fs.readFileSync(path.join(inputPath, '_prelude.vertex.glsl'));
-var fragmentPrelude = fs.readFileSync(path.join(inputPath, '_prelude.fragment.glsl'));
-var vertexSource = vertexPrelude + fs.readFileSync(path.join(inputPath, shaderName + '.vertex.glsl'), 'utf8');
-var fragmentSource = fragmentPrelude + fs.readFileSync(path.join(inputPath, shaderName + '.fragment.glsl'), 'utf8');
-
-var content = "#pragma once\n" +
-"\n" +
-"// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n" +
-"\n" +
-"#include <mbgl/gl/gl.hpp>\n" +
-"\n" +
-"namespace mbgl {\n" +
-"namespace shaders {\n" +
-"\n" +
-"class " + shaderName + " {\n" +
-"public:\n" +
-" static constexpr const char* name = \"" + shaderName + "\";\n" +
-" static constexpr const char* vertexSource = R\"MBGL_SHADER(" + applyPragmas(vertexSource) + ")MBGL_SHADER\";\n" +
-" static constexpr const char* fragmentSource = R\"MBGL_SHADER(" + applyPragmas(fragmentSource) + ")MBGL_SHADER\";\n" +
-"};\n" +
-"\n" +
-"} // namespace shaders\n" +
-"} // namespace mbgl\n";
-
-mkdirp.sync(outputPath);
-fs.writeFileSync(path.join(outputPath, shaderName + '.hpp'), content);
diff --git a/scripts/build-version.js b/scripts/build-version.js
deleted file mode 100755
index eb8a00f72c..0000000000
--- a/scripts/build-version.js
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env node
-
-var path = require('path');
-var fs = require('fs');
-var util = require('util');
-var mkdirp = require('mkdirp');
-var execSync = require('child_process').execSync;
-
-const DEFAULT_TAG = [0, 0, 0];
-const DEFAULT_REV = 'unknown';
-
-function is_git_repo() {
- try {
- execSync('git rev-parse', { stdio: ['ignore', 'ignore', 'ignore'] });
- return true;
- } catch(err) {
- return false;
- }
-}
-
-
-function parse_tag(raw_tag) {
- return raw_tag.replace(/[^0-9.]/g, '').split('.').map(parseFloat).slice(0, 3);
-}
-
-function parse_rev(raw_rev) {
- return raw_rev.substr(0, 8);
-}
-
-var output_dir = process.argv[2];
-
-if (!output_dir) {
- console.warn('No output directory given.');
- console.warn('Usage: %s [output dir]', path.basename(process.argv[1]));
- process.exit(1);
-}
-
-if (is_git_repo()) {
- var raw_tag = execSync('git describe --tags --always --abbrev=0').toString().trim();
- var raw_rev = execSync('git rev-parse HEAD').toString().trim();
-
- // When they're identical, the "git describe" can't find a tag and reports the rev instead.
- if (raw_tag == raw_rev) {
- var tag = DEFAULT_TAG
- var rev = parse_rev(raw_rev)
- } else {
- var tag = parse_tag(raw_tag)
- var rev = parse_rev(raw_rev)
- }
-} else {
- var tag = DEFAULT_TAG;
- var rev = DEFAULT_REV;
-}
-
-console.log('Tag: %d.%d.%d', tag[0], tag[1], tag[2]);
-console.log('Rev: %s', rev);
-
-var header = '// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.\n' +
- '#pragma once\n' +
- '\n' +
- '#define MBGL_VERSION 0x' + (tag[0] << 16 | tag[1] << 8 | tag[2]).toString(16) + '\n' +
- '#define MBGL_VERSION_STRING "' + tag[0] + '.' + tag[1] + '.' + tag[2] + '"\n' +
- '#define MBGL_VERSION_MAJOR ' + tag[0] + '\n' +
- '#define MBGL_VERSION_MINOR ' + tag[1] + '\n' +
- '#define MBGL_VERSION_PATCH ' + tag[2] + '\n' +
- '#define MBGL_VERSION_REV "' + rev + '"\n' +
- '\n' +
- 'namespace mbgl {\n' +
- 'namespace version {\n' +
- '\n' +
- 'extern const int major, minor, patch;\n' +
- 'extern const char *revision;\n' +
- 'extern const char *string;\n' +
- 'extern const unsigned int number;\n' +
- '\n' +
- '} // namespace version\n' +
- '} // namespace mbgl\n';
-
-var header_path = path.join(output_dir, 'include/mbgl/util/version.hpp')
-mkdirp.sync(path.dirname(header_path));
-fs.writeFileSync(header_path, header);
diff --git a/scripts/clang-tools.sh b/scripts/clang-tools.sh
index ae3a5fa0e7..2a330a5ee4 100755
--- a/scripts/clang-tools.sh
+++ b/scripts/clang-tools.sh
@@ -3,10 +3,8 @@
set -e
set -o pipefail
-export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
-
-CLANG_TIDY=${CLANG_TIDY:-$(mason prefix clang-tidy 3.9.1)/bin/clang-tidy}
-CLANG_FORMAT=${CLANG_FORMAT:-$(mason prefix clang-format 3.9.1)/bin/clang-format}
+CLANG_TIDY=${CLANG_TIDY:-$(scripts/mason.sh PREFIX clang-tidy VERSION 3.9.1)/bin/clang-tidy}
+CLANG_FORMAT=${CLANG_FORMAT:-$(scripts/mason.sh PREFIX clang-format VERSION 3.9.1)/bin/clang-format}
command -v ${CLANG_TIDY} >/dev/null 2>&1 || {
echo "Can't find ${CLANG_TIDY} in PATH."
diff --git a/scripts/codestyle.sh b/scripts/codestyle.sh
new file mode 100755
index 0000000000..3ed74f17c2
--- /dev/null
+++ b/scripts/codestyle.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+# Treats all characters as bytes, removes Unicode awareness from (broken?) macOS sed.
+export LC_ALL=C
+
+if [ `uname -s` = 'Darwin' ]; then
+ # BSD sed accepts a file extension.
+ SED="sed -i''"
+else
+ # GNU sed does not.
+ SED="sed -i"
+fi
+
+# Gather list of files
+FILES=$(git ls-files "*.hpp" "*.cpp" "*.h" "*.mm" "*.m" "*.c" "*.java" "*.xml" "*.ejs" "*.gradle" |
+ sed '/^platform\/android\/MapboxGLAndroidSDK\/src\/main\/java\/com\/almeros\// d;/^src\/clipper\// d;/^platform\/ios\/uitest\/OCMock/d')
+
+# Adds trailing newlines to files.
+echo "Checking for missing trailing newlines..."
+echo "${FILES}" | tr '\n' '\0' | xargs -0 ${SED} -e '$a\'
+
+# Removes trailing whitespace.
+echo "Checking for trailing whitespace..."
+echo "${FILES}" | tr '\n' '\0' | xargs -0 ${SED} 's/ *$// '
+
+# Add space after // comments. Does not replace // within double quotes.
+# Part of the regex is from http://stackoverflow.com/a/11503678
+echo "Checking for missing spaces after comments..."
+echo "${FILES}" | tr '\n' '\0' | xargs -0 perl -p -i -e 's/(?<!(:|\/))\/\/(?=[^ \/\n])(?=(?:[^"]*"[^"]*")*[^"]*\Z)/\/\/ /g'
+
+git diff --exit-code -- ${FILES} || {
+ echo "Some files were modified during code style checking."
+ exit 1
+}
diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js
new file mode 100755
index 0000000000..2949ebd007
--- /dev/null
+++ b/scripts/generate-shaders.js
@@ -0,0 +1,100 @@
+#!/usr/bin/env node
+
+const path = require('path');
+const fs = require('fs');
+
+const inputPath = 'mapbox-gl-js/src/shaders';
+const outputPath = 'src/mbgl/shaders';
+
+require('./style-code');
+
+[
+ 'circle',
+ 'collision_box',
+ 'debug',
+ 'fill',
+ 'fill_outline',
+ 'fill_outline_pattern',
+ 'fill_pattern',
+ 'line',
+ 'line_pattern',
+ 'line_sdf',
+ 'raster',
+ 'symbol_icon',
+ 'symbol_sdf'
+].forEach(function (shaderName) {
+ function applyPragmas(source, pragmas) {
+ return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => {
+ return pragmas[operation]
+ .join("\n")
+ .replace(/\{type\}/g, type)
+ .replace(/\{precision\}/g, precision)
+ .replace(/\{name\}/g, name);
+ });
+ }
+
+ function vertexSource() {
+ const prelude = fs.readFileSync(path.join(inputPath, '_prelude.vertex.glsl'));
+ const source = fs.readFileSync(path.join(inputPath, shaderName + '.vertex.glsl'), 'utf8');
+ return prelude + applyPragmas(source, {
+ define: [
+ "uniform lowp float a_{name}_t;",
+ "attribute {precision} {type} a_{name}_min;",
+ "attribute {precision} {type} a_{name}_max;",
+ "varying {precision} {type} {name};"
+ ],
+ initialize: [
+ "{name} = mix(a_{name}_min, a_{name}_max, a_{name}_t);"
+ ]
+ });
+ }
+
+ function fragmentSource() {
+ const prelude = fs.readFileSync(path.join(inputPath, '_prelude.fragment.glsl'));
+ const source = fs.readFileSync(path.join(inputPath, shaderName + '.fragment.glsl'), 'utf8');
+ return prelude + applyPragmas(source, {
+ define: [
+ "varying {precision} {type} {name};"
+ ],
+ initialize: [
+ ]
+ });
+ }
+
+ writeIfModified(path.join(outputPath, `${shaderName}.hpp`), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class ${shaderName} {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
+`);
+
+ writeIfModified(path.join(outputPath, `${shaderName}.cpp`), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/${shaderName}.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* ${shaderName}::name = "${shaderName}";
+const char* ${shaderName}::vertexSource = R"MBGL_SHADER(
+${vertexSource()}
+)MBGL_SHADER";
+const char* ${shaderName}::fragmentSource = R"MBGL_SHADER(
+${fragmentSource()}
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
+`);
+});
diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js
index f2acb12a2a..9629c8fe45 100644
--- a/scripts/generate-style-code.js
+++ b/scripts/generate-style-code.js
@@ -2,7 +2,7 @@
const fs = require('fs');
const ejs = require('ejs');
-const spec = require('mapbox-gl-style-spec').latest;
+const spec = require('../mapbox-gl-js/src/style-spec/reference/v8');
const colorParser = require('csscolorparser');
require('./style-code');
@@ -14,7 +14,11 @@ function parseCSSColor(str) {
];
}
-global.propertyType = function (property) {
+global.isDataDriven = function (property) {
+ return property['property-function'] === true;
+};
+
+global.evaluatedType = function (property) {
if (/-translate-anchor$/.test(property.name)) {
return 'TranslateAnchorType';
}
@@ -34,14 +38,58 @@ global.propertyType = function (property) {
return `Color`;
case 'array':
if (property.length) {
- return `std::array<${propertyType({type: property.value})}, ${property.length}>`;
+ return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`;
} else {
- return `std::vector<${propertyType({type: property.value})}>`;
+ return `std::vector<${evaluatedType({type: property.value})}>`;
}
default: throw new Error(`unknown type for ${property.name}`)
}
};
+function attributeType(property, type) {
+ const attributeNameExceptions = {
+ 'text-opacity': 'opacity',
+ 'icon-opacity': 'opacity',
+ 'text-color': 'fill_color',
+ 'icon-color': 'fill_color',
+ 'text-halo-color': 'halo_color',
+ 'icon-halo-color': 'halo_color',
+ 'text-halo-blur': 'halo_blur',
+ 'icon-halo-blur': 'halo_blur',
+ 'text-halo-width': 'halo_width',
+ 'icon-halo-width': 'halo_width'
+ }
+ const name = attributeNameExceptions[property.name] ||
+ property.name.replace(type + '-', '').replace(/-/g, '_');
+ return `attributes::a_${name}${name === 'offset' ? '<1>' : ''}`;
+}
+
+global.layoutPropertyType = function (property) {
+ if (isDataDriven(property)) {
+ return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
+ } else {
+ return `LayoutProperty<${evaluatedType(property)}>`;
+ }
+};
+
+global.paintPropertyType = function (property, type) {
+ if (isDataDriven(property)) {
+ return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeType(property, type)}>`;
+ } else if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') {
+ return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
+ } else {
+ return `PaintProperty<${evaluatedType(property)}>`;
+ }
+};
+
+global.propertyValueType = function (property) {
+ if (isDataDriven(property)) {
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ } else {
+ return `PropertyValue<${evaluatedType(property)}>`;
+ }
+};
+
global.defaultValue = function (property) {
// https://github.com/mapbox/mapbox-gl-native/issues/5258
if (property.name === 'line-round-limit') {
@@ -59,9 +107,9 @@ global.defaultValue = function (property) {
return JSON.stringify(property.default || "");
case 'enum':
if (property.default === undefined) {
- return `${propertyType(property)}::Undefined`;
+ return `${evaluatedType(property)}::Undefined`;
} else {
- return `${propertyType(property)}::${camelize(property.default)}`;
+ return `${evaluatedType(property)}::${camelize(property.default)}`;
}
case 'color':
const color = parseCSSColor(property.default).join(', ');
diff --git a/scripts/log_memory_benchmarks.sh b/scripts/log_memory_benchmarks.sh
new file mode 100755
index 0000000000..1f213caa92
--- /dev/null
+++ b/scripts/log_memory_benchmarks.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+set -u
+
+# Logs metrics on memory usage to CloudWatch
+
+GTEST_OUTPUT=$1
+DIMENSIONS=$2
+
+if [ -z "${DIMENSIONS}" ]; then
+ echo "* No dimensions specified for memory benchmarks"
+ exit 1
+fi
+
+function reportAttributeValue {
+ ATTR_NAME=$1
+ ATTR_UNITS=$2
+ ATTR_VALUE=$(cat $GTEST_OUTPUT | grep -o "$ATTR_NAME=\"[^\"]*" | sed "s/$ATTR_NAME=\"//")
+ if [ ${CLOUDWATCH:-} ]; then
+ echo "* Reporting $ATTR_NAME = $ATTR_VALUE $ATTR_UNITS for '${DIMENSIONS}'"
+ aws --region us-east-1 cloudwatch put-metric-data \
+ --namespace "Mapbox/GL" \
+ --metric-name "$ATTR_NAME" \
+ --unit "$ATTR_UNITS" \
+ --value ${ATTR_VALUE} \
+ --dimensions "${DIMENSIONS}"
+ else
+ echo "* Measured $ATTR_NAME = $ATTR_VALUE $ATTR_UNITS for '${DIMENSIONS}'"
+ fi
+}
+
+if [ -f "${GTEST_OUTPUT}" ]; then
+ reportAttributeValue vectorFootprint Bytes
+ reportAttributeValue rasterFootprint Bytes
+else
+ echo "* File '${GTEST_OUTPUT}' does not exist"
+fi
diff --git a/scripts/mason.sh b/scripts/mason.sh
new file mode 100755
index 0000000000..696ad26adb
--- /dev/null
+++ b/scripts/mason.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+cmake -P cmake/mason.cmake "$@"
diff --git a/scripts/travis_setup.sh b/scripts/travis_setup.sh
index 65a2945fdc..20a708d20a 100755
--- a/scripts/travis_setup.sh
+++ b/scripts/travis_setup.sh
@@ -29,16 +29,18 @@ if [ -x $(which ${CXX}) ]; then
${CXX} --version
fi
-# Ensure mason is on the PATH
-export PATH="`pwd`/.mason:${PATH}" MASON_DIR="`pwd`/.mason"
-
-mapbox_time "checkout_mason" \
-git submodule update --init .mason
-
# Touch package.json so that we are definitely going to run an npm update action
mapbox_time "touch_package_json" \
touch package.json
+function mapbox_install_logbt {
+ scripts/mason.sh INSTALL gdb VERSION 7.12
+ export PATH=$(scripts/mason.sh PREFIX gdb VERSION 7.12)/bin:${PATH}
+ curl -sSfL https://github.com/mapbox/logbt/archive/v2.0.1.tar.gz | tar --gunzip --extract --strip-components=2 --exclude="*md" --exclude="test*" --directory=.
+ sudo ./logbt --setup
+ ./logbt --test
+}
+
function mapbox_start_xvfb {
if [ ! -f /etc/init.d/xvfb ]; then
echo "Error: Could not start Xvfb mock server."
@@ -58,8 +60,11 @@ export -f mapbox_start_xvfb
function mapbox_export_mesa_library_path {
# Install and set up to load a more recent version of mesa
mapbox_time "install_mesa" \
- mason install mesa 13.0.0-glx
- export LD_LIBRARY_PATH="`mason prefix mesa 13.0.0-glx`/lib:${LD_LIBRARY_PATH:-}"
+ scripts/mason.sh install mesa VERSION 13.0.4
+
+ MESA_PREFIX=`scripts/mason.sh PREFIX mesa VERSION 13.0.4`
+ export LD_LIBRARY_PATH="${MESA_PREFIX}/lib:${LD_LIBRARY_PATH:-}"
+ export LIBGL_DRIVERS_PATH="${MESA_PREFIX}/lib/dri"
}
export -f mapbox_export_mesa_library_path
diff --git a/scripts/update_ca_bundle.sh b/scripts/update_ca_bundle.sh
new file mode 100755
index 0000000000..992bd7030f
--- /dev/null
+++ b/scripts/update_ca_bundle.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+cd common
+curl https://raw.githubusercontent.com/curl/curl/master/lib/mk-ca-bundle.pl | perl
+rm certdata.txt
diff --git a/scripts/valgrind.sh b/scripts/valgrind.sh
index c717fc2cb8..4eeb9c9785 100755
--- a/scripts/valgrind.sh
+++ b/scripts/valgrind.sh
@@ -3,7 +3,7 @@
set -e
set -o pipefail
-.mason/mason install valgrind 3.12.0
+VALGRIND_PREFIX=$(scripts/mason.sh PREFIX valgrind VERSION 3.12.0)
PARAMS="\
--leak-check=full \
@@ -13,6 +13,6 @@ PARAMS="\
--gen-suppressions=all \
--suppressions=scripts/valgrind.sup"
-export VALGRIND_LIB=$(.mason/mason prefix valgrind 3.12.0)/lib/valgrind
+export VALGRIND_LIB=${VALGRIND_PREFIX}/lib/valgrind
-$(.mason/mason prefix valgrind 3.12.0)/bin/valgrind $PARAMS $@
+${VALGRIND_PREFIX}/bin/valgrind $PARAMS $@
diff --git a/scripts/valgrind.sup b/scripts/valgrind.sup
index ea3e3d635a..fc6bfaac58 100644
--- a/scripts/valgrind.sup
+++ b/scripts/valgrind.sup
@@ -266,3 +266,74 @@
fun:_ZN4mbgl4util10write_fileERKSsS2_
...
}
+{
+ Ubuntu 14.04 - Travis + mesa 13.0.3
+ Memcheck:Cond
+ fun:_ZN12_GLOBAL__N_117PeepholeOptimizer20runOnMachineFunctionERN4llvm15MachineFunctionE
+ fun:_ZN4llvm19MachineFunctionPass13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE
+ fun:_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE
+ fun:_ZN4llvm5MCJIT10emitObjectEPNS_6ModuleE
+ fun:_ZN4llvm5MCJIT21generateCodeForModuleEPNS_6ModuleE
+ fun:_ZN4llvm5MCJIT14finalizeObjectEv
+ fun:LLVMGetPointerToGlobal
+ fun:gallivm_jit_function
+ fun:generate_variant
+ fun:llvmpipe_update_fs
+}
+{
+ Ubuntu 14.04 - Travis + mesa 13.0.3
+ Memcheck:Cond
+ fun:_ZNK4llvm12X86InstrInfo13reMaterializeERNS_17MachineBasicBlockENS1_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS4_EEEEjjPKS4_RKNS_18TargetRegisterInfoE
+ fun:_ZN12_GLOBAL__N_117RegisterCoalescer23reMaterializeTrivialDefERKN4llvm13CoalescerPairEPNS1_12MachineInstrERb
+ fun:_ZN12_GLOBAL__N_117RegisterCoalescer8joinCopyEPN4llvm12MachineInstrERb
+ fun:_ZN12_GLOBAL__N_117RegisterCoalescer20runOnMachineFunctionERN4llvm15MachineFunctionE
+ fun:_ZN4llvm19MachineFunctionPass13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE
+ fun:_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE
+ fun:_ZN4llvm5MCJIT10emitObjectEPNS_6ModuleE
+ fun:_ZN4llvm5MCJIT21generateCodeForModuleEPNS_6ModuleE
+ fun:_ZN4llvm5MCJIT14finalizeObjectEv
+ fun:LLVMGetPointerToGlobal
+}
+{
+ Ubuntu 14.04 - Travis + mesa 13.0.3
+ Memcheck:Cond
+ fun:_ZNK4llvm12X86InstrInfo13reMaterializeERNS_17MachineBasicBlockENS1_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS4_EEEEjjPKS4_RKNS_18TargetRegisterInfoE
+ fun:_ZN4llvm13LiveRangeEdit15rematerializeAtERNS_17MachineBasicBlockENS1_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS4_EEEEjRKNS0_5RematERKNS_18TargetRegisterInfoEb
+ fun:_ZN12_GLOBAL__N_113InlineSpiller5spillERN4llvm13LiveRangeEditE
+ fun:_ZN12_GLOBAL__N_18RAGreedy17selectOrSplitImplERN4llvm12LiveIntervalERNS1_15SmallVectorImplIjEERNS1_8SmallSetIjLj16ESt4lessIjEEEj
+ fun:_ZN12_GLOBAL__N_18RAGreedy13selectOrSplitERN4llvm12LiveIntervalERNS1_15SmallVectorImplIjEE
+ fun:_ZN4llvm12RegAllocBase16allocatePhysRegsEv
+ fun:_ZN12_GLOBAL__N_18RAGreedy20runOnMachineFunctionERN4llvm15MachineFunctionE
+ fun:_ZN4llvm19MachineFunctionPass13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE
+ fun:_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE
+ fun:_ZN4llvm5MCJIT10emitObjectEPNS_6ModuleE
+}
+{
+ Ubuntu 14.04 - Travis + mesa 13.0.3
+ Memcheck:Cond
+ fun:_ZNK4llvm12X86InstrInfo13reMaterializeERNS_17MachineBasicBlockENS1_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS4_EEEEjjPKS4_RKNS_18TargetRegisterInfoE
+ fun:_ZN4llvm13LiveRangeEdit15rematerializeAtERNS_17MachineBasicBlockENS1_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS4_EEEEjRKNS0_5RematERKNS_18TargetRegisterInfoEb
+ fun:_ZN4llvm11SplitEditor13defFromParentEjPNS_6VNInfoENS_9SlotIndexERNS_17MachineBasicBlockENS4_15bundle_iteratorINS_12MachineInstrENS_14ilist_iteratorIS7_EEEE
+ fun:_ZN4llvm11SplitEditor16splitRegOutBlockERKNS_13SplitAnalysis9BlockInfoEjNS_9SlotIndexE
+ fun:_ZN12_GLOBAL__N_18RAGreedy13doRegionSplitERN4llvm12LiveIntervalEjbRNS1_15SmallVectorImplIjEE
+ fun:_ZN12_GLOBAL__N_18RAGreedy17selectOrSplitImplERN4llvm12LiveIntervalERNS1_15SmallVectorImplIjEERNS1_8SmallSetIjLj16ESt4lessIjEEEj
+ fun:_ZN12_GLOBAL__N_18RAGreedy13selectOrSplitERN4llvm12LiveIntervalERNS1_15SmallVectorImplIjEE
+ fun:_ZN4llvm12RegAllocBase16allocatePhysRegsEv
+ fun:_ZN12_GLOBAL__N_18RAGreedy20runOnMachineFunctionERN4llvm15MachineFunctionE
+ fun:_ZN4llvm19MachineFunctionPass13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE
+ fun:_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE
+}
+{
+ Ubuntu 14.04 - Travis + mesa 13.0.3
+ Memcheck:Leak
+ match-leak-kinds: definite
+ fun:_Znwm
+ ...
+}
diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp
index f8c1c3adf7..ed1518fb7b 100644
--- a/src/mbgl/annotation/annotation_manager.cpp
+++ b/src/mbgl/annotation/annotation_manager.cpp
@@ -90,7 +90,7 @@ void AnnotationManager::add(const AnnotationID& id, const StyleSourcedAnnotation
Update AnnotationManager::update(const AnnotationID& id, const SymbolAnnotation& annotation, const uint8_t maxZoom) {
Update result = Update::Nothing;
-
+
auto it = symbolAnnotations.find(id);
if (it == symbolAnnotations.end()) {
assert(false); // Attempt to update a non-existent symbol annotation
@@ -222,12 +222,10 @@ void AnnotationManager::removeTile(AnnotationTile& tile) {
void AnnotationManager::addIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
spriteAtlas.setSprite(name, sprite);
- spriteAtlas.updateDirty();
}
void AnnotationManager::removeIcon(const std::string& name) {
spriteAtlas.removeSprite(name);
- spriteAtlas.updateDirty();
}
double AnnotationManager::getTopOffsetPixelsForIcon(const std::string& name) {
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index 7432fff590..2c16dac3fc 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -1,29 +1,238 @@
#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/context.hpp>
#include <mbgl/gl/gl.hpp>
+#include <mbgl/gl/normalization.hpp>
namespace mbgl {
namespace gl {
+static_assert(offsetof(Normalized<uint8_t>, value) == 0, "unexpected normalized offset");
+
AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
return location;
}
-void bindAttribute(AttributeLocation location,
- std::size_t count,
- DataType type,
- std::size_t vertexSize,
- std::size_t vertexOffset,
- std::size_t attributeOffset) {
+template <class T> DataType DataTypeOf = static_cast<DataType>(0);
+template <> DataType DataTypeOf< int8_t> = DataType::Byte;
+template <> DataType DataTypeOf<uint8_t> = DataType::UnsignedByte;
+template <> DataType DataTypeOf< int16_t> = DataType::Short;
+template <> DataType DataTypeOf<uint16_t> = DataType::UnsignedShort;
+template <> DataType DataTypeOf< int32_t> = DataType::Integer;
+template <> DataType DataTypeOf<uint32_t> = DataType::UnsignedInteger;
+template <> DataType DataTypeOf<float> = DataType::Float;
+
+template <class T> bool IsNormalized = false;
+template <class T> bool IsNormalized<Normalized<T>> = true;
+template <class T> DataType DataTypeOf<Normalized<T>> = DataTypeOf<T>;
+
+template <class T, std::size_t N>
+void VariableAttributeBinding<T, N>::bind(Context& context,
+ AttributeLocation location,
+ optional<VariableAttributeBinding<T, N>>& oldBinding,
+ std::size_t vertexOffset) const {
+ if (oldBinding == *this) {
+ return;
+ }
+ context.vertexBuffer = vertexBuffer;
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
MBGL_CHECK_ERROR(glVertexAttribPointer(
location,
- static_cast<GLint>(count),
- static_cast<GLenum>(type),
- GL_FALSE,
+ static_cast<GLint>(N),
+ static_cast<GLenum>(DataTypeOf<T>),
+ static_cast<GLboolean>(IsNormalized<T>),
static_cast<GLsizei>(vertexSize),
reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset))));
}
+template class VariableAttributeBinding<uint8_t, 1>;
+template class VariableAttributeBinding<uint8_t, 2>;
+template class VariableAttributeBinding<uint8_t, 3>;
+template class VariableAttributeBinding<uint8_t, 4>;
+
+template class VariableAttributeBinding<Normalized<uint8_t>, 1>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 2>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 3>;
+template class VariableAttributeBinding<Normalized<uint8_t>, 4>;
+
+template class VariableAttributeBinding<uint16_t, 1>;
+template class VariableAttributeBinding<uint16_t, 2>;
+template class VariableAttributeBinding<uint16_t, 3>;
+template class VariableAttributeBinding<uint16_t, 4>;
+
+template class VariableAttributeBinding<int16_t, 1>;
+template class VariableAttributeBinding<int16_t, 2>;
+template class VariableAttributeBinding<int16_t, 3>;
+template class VariableAttributeBinding<int16_t, 4>;
+
+template class VariableAttributeBinding<float, 1>;
+template class VariableAttributeBinding<float, 2>;
+template class VariableAttributeBinding<float, 3>;
+template class VariableAttributeBinding<float, 4>;
+
+template <>
+void ConstantAttributeBinding<uint8_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<uint8_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint8_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0].denormalized(), value[1].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized()));
+}
+
+template <>
+void ConstantAttributeBinding<Normalized<uint8_t>, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<Normalized<uint8_t>, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0].denormalized(), value[1].denormalized(), value[2].denormalized(), value[3].denormalized()));
+}
+
+
+template <>
+void ConstantAttributeBinding<uint16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<uint16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<uint16_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<int16_t, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<int16_t, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<int16_t, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
+
+template <>
+void ConstantAttributeBinding<float, 1>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 1>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib1f(location, value[0]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 2>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 2>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib2f(location, value[0], value[1]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 3>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 3>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib3f(location, value[0], value[1], value[2]));
+}
+
+template <>
+void ConstantAttributeBinding<float, 4>::bind(Context&, AttributeLocation location, optional<VariableAttributeBinding<float, 4>>& oldBinding, std::size_t) const {
+ assert(location != 0);
+ oldBinding = {};
+ MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
+ MBGL_CHECK_ERROR(glVertexAttrib4f(location, value[0], value[1], value[2], value[3]));
+}
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index e45014127b..6300ebb56b 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -1,8 +1,10 @@
#pragma once
#include <mbgl/gl/types.hpp>
+#include <mbgl/gl/segment.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/indexed_tuple.hpp>
+#include <mbgl/util/variant.hpp>
#include <cstddef>
#include <functional>
@@ -10,24 +12,79 @@
namespace mbgl {
namespace gl {
-template <class Tag, class T, std::size_t N>
+template <class T, std::size_t N>
+class VariableAttributeBinding {
+public:
+ VariableAttributeBinding(BufferID vertexBuffer_,
+ std::size_t vertexSize_,
+ std::size_t attributeOffset_)
+ : vertexBuffer(vertexBuffer_),
+ vertexSize(vertexSize_),
+ attributeOffset(attributeOffset_)
+ {}
+
+ void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t vertexOffset) const;
+
+ friend bool operator==(const VariableAttributeBinding& lhs,
+ const VariableAttributeBinding& rhs) {
+ return lhs.vertexBuffer == rhs.vertexBuffer
+ && lhs.vertexSize == rhs.vertexSize
+ && lhs.attributeOffset == rhs.attributeOffset;
+ }
+
+private:
+ BufferID vertexBuffer;
+ std::size_t vertexSize;
+ std::size_t attributeOffset;
+};
+
+template <class T, std::size_t N>
+class ConstantAttributeBinding {
+public:
+ ConstantAttributeBinding() { value.fill(T()); }
+
+ explicit ConstantAttributeBinding(std::array<T, N> value_)
+ : value(std::move(value_))
+ {}
+
+ void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t) const;
+
+ friend bool operator==(const ConstantAttributeBinding& lhs,
+ const ConstantAttributeBinding& rhs) {
+ return lhs.value == rhs.value;
+ }
+
+private:
+ std::array<T, N> value;
+};
+
+template <class T, std::size_t N>
class Attribute {
public:
- using Type = T[N];
+ using Value = std::array<T, N>;
+
+ using VariableBinding = VariableAttributeBinding<T, N>;
+ using ConstantBinding = ConstantAttributeBinding<T, N>;
- class State {
- public:
- explicit State(AttributeLocation location_)
- : location(location_) {}
+ using Location = AttributeLocation;
- AttributeLocation location;
- static constexpr std::size_t count = N;
- static constexpr DataType type = DataTypeOf<T>::value;
- };
+ using Binding = variant<
+ ConstantBinding,
+ VariableBinding>;
+
+ static void bind(Context& context,
+ const Location& location,
+ optional<VariableBinding>& oldBinding,
+ const Binding& newBinding,
+ std::size_t vertexOffset) {
+ Binding::visit(newBinding, [&] (const auto& binding) {
+ binding.bind(context, location, oldBinding, vertexOffset);
+ });
+ }
};
#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \
- struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::Attribute<type_, n_> { static auto name() { return #name_; } }
namespace detail {
@@ -41,10 +98,16 @@ namespace detail {
template <class... As>
class Vertex;
+template <>
+class Vertex<> {
+public:
+ using VertexType = Vertex<>;
+};
+
template <class A1>
class Vertex<A1> {
public:
- typename A1::Type a1;
+ typename A1::Value a1;
using VertexType = Vertex<A1>;
static const std::size_t attributeOffsets[1];
@@ -53,8 +116,8 @@ public:
template <class A1, class A2>
class Vertex<A1, A2> {
public:
- typename A1::Type a1;
- typename A2::Type a2;
+ typename A1::Value a1;
+ typename A2::Value a2;
using VertexType = Vertex<A1, A2>;
static const std::size_t attributeOffsets[2];
@@ -63,9 +126,9 @@ public:
template <class A1, class A2, class A3>
class Vertex<A1, A2, A3> {
public:
- typename A1::Type a1;
- typename A2::Type a2;
- typename A3::Type a3;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
using VertexType = Vertex<A1, A2, A3>;
static const std::size_t attributeOffsets[3];
@@ -74,10 +137,10 @@ public:
template <class A1, class A2, class A3, class A4>
class Vertex<A1, A2, A3, A4> {
public:
- typename A1::Type a1;
- typename A2::Type a2;
- typename A3::Type a3;
- typename A4::Type a4;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
+ typename A4::Value a4;
using VertexType = Vertex<A1, A2, A3, A4>;
static const std::size_t attributeOffsets[4];
@@ -86,11 +149,11 @@ public:
template <class A1, class A2, class A3, class A4, class A5>
class Vertex<A1, A2, A3, A4, A5> {
public:
- typename A1::Type a1;
- typename A2::Type a2;
- typename A3::Type a3;
- typename A4::Type a4;
- typename A5::Type a5;
+ typename A1::Value a1;
+ typename A2::Value a2;
+ typename A3::Value a3;
+ typename A4::Value a4;
+ typename A5::Value a5;
using VertexType = Vertex<A1, A2, A3, A4, A5>;
static const std::size_t attributeOffsets[5];
@@ -135,37 +198,71 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
-void bindAttribute(AttributeLocation location,
- std::size_t count,
- DataType type,
- std::size_t vertexSize,
- std::size_t vertexOffset,
- std::size_t attributeOffset);
-
template <class... As>
class Attributes {
public:
- using State = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>;
+ using Types = TypeList<As...>;
+ using Locations = IndexedTuple<
+ TypeList<As...>,
+ TypeList<typename As::Location...>>;
+ using Bindings = IndexedTuple<
+ TypeList<As...>,
+ TypeList<typename As::Binding...>>;
+ using VariableBindings = IndexedTuple<
+ TypeList<As...>,
+ TypeList<optional<typename As::VariableBinding>...>>;
+
using Vertex = detail::Vertex<As...>;
template <class A>
static constexpr std::size_t Index = TypeIndex<A, As...>::value;
- static State state(const ProgramID& id) {
- return State { typename As::State(bindAttributeLocation(id, Index<As>, As::name))... };
+ static Locations locations(const ProgramID& id) {
+ return Locations { bindAttributeLocation(id, Index<As>, As::name())... };
}
- static std::function<void (std::size_t)> binder(const State& state) {
- return [&state] (std::size_t vertexOffset) {
- util::ignore({ (bindAttribute(state.template get<As>().location,
- state.template get<As>().count,
- state.template get<As>().type,
- sizeof(Vertex),
- vertexOffset,
- Vertex::attributeOffsets[Index<As>]), 0)... });
+ template <class DrawMode>
+ static Bindings allVariableBindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
+ static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+
+ return Bindings {
+ typename As::VariableBinding {
+ buffer.buffer,
+ sizeof(Vertex),
+ Vertex::attributeOffsets[Index<As>]
+ }...
};
}
+
+ static void bind(Context& context,
+ const Locations& locations,
+ VariableBindings& oldBindings,
+ const Bindings& newBindings,
+ std::size_t vertexOffset) {
+ util::ignore({ (As::bind(context,
+ locations.template get<As>(),
+ oldBindings.template get<As>(),
+ newBindings.template get<As>(),
+ vertexOffset), 0)... });
+ }
};
+namespace detail {
+
+template <class...>
+struct ConcatenateAttributes;
+
+template <class... As, class... Bs>
+struct ConcatenateAttributes<TypeList<As...>, TypeList<Bs...>> {
+ using Type = Attributes<As..., Bs...>;
+};
+
+} // namespace detail
+
+template <class A, class B>
+using ConcatenateAttributes = typename detail::ConcatenateAttributes<
+ typename A::Types,
+ typename B::Types>::Type;
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp
index 5048ffcd66..9c2031ccfd 100644
--- a/src/mbgl/gl/context.cpp
+++ b/src/mbgl/gl/context.cpp
@@ -122,6 +122,20 @@ UniqueTexture Context::createTexture() {
return UniqueTexture{ std::move(id), { this } };
}
+bool Context::supportsVertexArrays() const {
+ return gl::GenVertexArrays &&
+ gl::BindVertexArray &&
+ gl::DeleteVertexArrays &&
+ !disableVAOExtension;
+}
+
+UniqueVertexArray Context::createVertexArray() {
+ assert(supportsVertexArrays());
+ VertexArrayID id = 0;
+ MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
+ return UniqueVertexArray(std::move(id), { this });
+}
+
UniqueFramebuffer Context::createFramebuffer() {
FramebufferID id = 0;
MBGL_CHECK_ERROR(glGenFramebuffers(1, &id));
@@ -407,32 +421,26 @@ void Context::clear(optional<mbgl::Color> color,
}
#if not MBGL_USE_GLES2
-PrimitiveType Context::operator()(const Points& points) {
+void Context::setDrawMode(const Points& points) {
pointSize = points.pointSize;
- return PrimitiveType::Points;
}
#else
-PrimitiveType Context::operator()(const Points&) {
- return PrimitiveType::Points;
+void Context::setDrawMode(const Points&) {
}
#endif // MBGL_USE_GLES2
-PrimitiveType Context::operator()(const Lines& lines) {
+void Context::setDrawMode(const Lines& lines) {
lineWidth = lines.lineWidth;
- return PrimitiveType::Lines;
}
-PrimitiveType Context::operator()(const LineStrip& lineStrip) {
+void Context::setDrawMode(const LineStrip& lineStrip) {
lineWidth = lineStrip.lineWidth;
- return PrimitiveType::LineStrip;
}
-PrimitiveType Context::operator()(const Triangles&) {
- return PrimitiveType::Triangles;
+void Context::setDrawMode(const Triangles&) {
}
-PrimitiveType Context::operator()(const TriangleStrip&) {
- return PrimitiveType::TriangleStrip;
+void Context::setDrawMode(const TriangleStrip&) {
}
void Context::setDepthMode(const DepthMode& depth) {
@@ -474,57 +482,14 @@ void Context::setColorMode(const ColorMode& color) {
colorMask = color.mask;
}
-void Context::draw(const Drawable& drawable) {
- if (drawable.segments.empty()) {
- return;
- }
-
- PrimitiveType primitiveType = apply_visitor([&] (auto m) { return (*this)(m); }, drawable.drawMode);
-
- setDepthMode(drawable.depthMode);
- setStencilMode(drawable.stencilMode);
- setColorMode(drawable.colorMode);
-
- program = drawable.program;
-
- drawable.bindUniforms();
-
- for (const auto& segment : drawable.segments) {
- auto needAttributeBindings = [&] () {
- if (!gl::GenVertexArrays || !gl::BindVertexArray) {
- return true;
- }
-
- if (segment.vao) {
- vertexArrayObject = *segment.vao;
- return false;
- }
-
- VertexArrayID id = 0;
- MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
- vertexArrayObject = id;
- segment.vao = UniqueVertexArray(std::move(id), { this });
-
- // If we are initializing a new VAO, we need to force the buffers
- // to be rebound. VAOs don't inherit the existing buffer bindings.
- vertexBuffer.setDirty();
- elementBuffer.setDirty();
-
- return true;
- };
-
- if (needAttributeBindings()) {
- vertexBuffer = drawable.vertexBuffer;
- elementBuffer = drawable.indexBuffer;
- drawable.bindAttributes(segment.vertexOffset);
- }
-
- MBGL_CHECK_ERROR(glDrawElements(
- static_cast<GLenum>(primitiveType),
- static_cast<GLsizei>(segment.indexLength),
- GL_UNSIGNED_SHORT,
- reinterpret_cast<GLvoid*>(sizeof(uint16_t) * segment.indexOffset)));
- }
+void Context::draw(PrimitiveType primitiveType,
+ std::size_t indexOffset,
+ std::size_t indexLength) {
+ MBGL_CHECK_ERROR(glDrawElements(
+ static_cast<GLenum>(primitiveType),
+ static_cast<GLsizei>(indexLength),
+ GL_UNSIGNED_SHORT,
+ reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset)));
}
void Context::performCleanup() {
@@ -564,6 +529,7 @@ void Context::performCleanup() {
}
if (!abandonedVertexArrays.empty()) {
+ assert(supportsVertexArrays());
for (const auto id : abandonedVertexArrays) {
if (vertexArrayObject == id) {
vertexArrayObject.setDirty();
diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp
index 093afa20ed..9d3ecec662 100644
--- a/src/mbgl/gl/context.hpp
+++ b/src/mbgl/gl/context.hpp
@@ -13,7 +13,6 @@
#include <mbgl/gl/depth_mode.hpp>
#include <mbgl/gl/stencil_mode.hpp>
#include <mbgl/gl/color_mode.hpp>
-#include <mbgl/gl/segment.hpp>
#include <mbgl/util/noncopyable.hpp>
@@ -41,6 +40,9 @@ public:
void linkProgram(ProgramID);
UniqueTexture createTexture();
+ bool supportsVertexArrays() const;
+ UniqueVertexArray createVertexArray();
+
template <class Vertex, class DrawMode>
VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) {
return VertexBuffer<Vertex, DrawMode> {
@@ -119,25 +121,20 @@ public:
optional<float> depth,
optional<int32_t> stencil);
- struct Drawable {
- DrawMode drawMode;
- DepthMode depthMode;
- StencilMode stencilMode;
- ColorMode colorMode;
- gl::ProgramID program;
- gl::BufferID vertexBuffer;
- gl::BufferID indexBuffer;
- const std::vector<Segment>& segments;
- std::function<void ()> bindUniforms;
- std::function<void (std::size_t)> bindAttributes;
- };
-
- void draw(const Drawable&);
+ void setDrawMode(const Points&);
+ void setDrawMode(const Lines&);
+ void setDrawMode(const LineStrip&);
+ void setDrawMode(const Triangles&);
+ void setDrawMode(const TriangleStrip&);
void setDepthMode(const DepthMode&);
void setStencilMode(const StencilMode&);
void setColorMode(const ColorMode&);
+ void draw(PrimitiveType,
+ std::size_t indexOffset,
+ std::size_t indexLength);
+
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
void performCleanup();
@@ -164,6 +161,8 @@ public:
std::array<State<value::BindTexture>, 2> texture;
State<value::BindVertexArray> vertexArrayObject;
State<value::Program> program;
+ State<value::BindVertexBuffer> vertexBuffer;
+ State<value::BindElementBuffer> elementBuffer;
#if not MBGL_USE_GLES2
State<value::PixelZoom> pixelZoom;
@@ -196,8 +195,6 @@ private:
#if not MBGL_USE_GLES2
State<value::PointSize> pointSize;
#endif // MBGL_USE_GLES2
- State<value::BindVertexBuffer> vertexBuffer;
- State<value::BindElementBuffer> elementBuffer;
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
@@ -210,12 +207,6 @@ private:
void drawPixels(Size size, const void* data, TextureFormat);
#endif // MBGL_USE_GLES2
- PrimitiveType operator()(const Points&);
- PrimitiveType operator()(const Lines&);
- PrimitiveType operator()(const LineStrip&);
- PrimitiveType operator()(const Triangles&);
- PrimitiveType operator()(const TriangleStrip&);
-
friend detail::ProgramDeleter;
friend detail::ShaderDeleter;
friend detail::BufferDeleter;
@@ -233,6 +224,10 @@ private:
std::vector<VertexArrayID> abandonedVertexArrays;
std::vector<FramebufferID> abandonedFramebuffers;
std::vector<RenderbufferID> abandonedRenderbuffers;
+
+public:
+ // For testing
+ bool disableVAOExtension = false;
};
} // namespace gl
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp
index f99308de7e..5ce3e606ee 100644
--- a/src/mbgl/gl/debugging.cpp
+++ b/src/mbgl/gl/debugging.cpp
@@ -132,7 +132,7 @@ void enable() {
}
// This will enable all messages including performance hints
- //MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
+ // MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
// This will only enable high and medium severity messages
MBGL_CHECK_ERROR(DebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE));
diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp
index ab86d5e469..275eb25b89 100644
--- a/src/mbgl/gl/draw_mode.hpp
+++ b/src/mbgl/gl/draw_mode.hpp
@@ -1,7 +1,7 @@
#pragma once
+#include <mbgl/gl/types.hpp>
#include <mbgl/gl/primitives.hpp>
-#include <mbgl/util/variant.hpp>
#include <cassert>
@@ -11,7 +11,9 @@ namespace gl {
class Points {
public:
using Primitive = Point;
+
static constexpr std::size_t bufferGroupSize = 1;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Points;
explicit Points(float pointSize_) : pointSize(pointSize_) {}
@@ -21,7 +23,9 @@ public:
class Lines {
public:
using Primitive = Line;
+
static constexpr std::size_t bufferGroupSize = 2;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Lines;
explicit Lines(float lineWidth_) : lineWidth(lineWidth_) {
assert(lineWidth > 0);
@@ -35,7 +39,9 @@ public:
// LineStrip is a form of "Line" rendering, but the element buffer
// cannot be grouped into logical elements beyond a single Point.
using Primitive = Line;
+
static constexpr std::size_t bufferGroupSize = 1;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::LineStrip;
explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) {
assert(lineWidth > 0);
@@ -47,7 +53,9 @@ public:
class Triangles {
public:
using Primitive = Triangle;
+
static constexpr std::size_t bufferGroupSize = 3;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::Triangles;
};
class TriangleStrip {
@@ -55,7 +63,9 @@ public:
// TriangleStrip is a form of "Triangle" rendering, but the element buffer
// cannot be grouped into logical elements beyond a single Point.
using Primitive = Triangle;
+
static constexpr std::size_t bufferGroupSize = 1;
+ static constexpr PrimitiveType primitiveType = PrimitiveType::TriangleStrip;
};
// Special draw mode for use with VertexVector<Indexed, Vertex>, in which
@@ -65,12 +75,5 @@ public:
static constexpr std::size_t bufferGroupSize = 1;
};
-using DrawMode = variant<
- Points,
- Lines,
- LineStrip,
- Triangles,
- TriangleStrip>;
-
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/normalization.hpp b/src/mbgl/gl/normalization.hpp
new file mode 100644
index 0000000000..83fa67a3ec
--- /dev/null
+++ b/src/mbgl/gl/normalization.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+#include <mbgl/math/clamp.hpp>
+
+#include <cassert>
+#include <limits>
+
+namespace mbgl {
+namespace gl {
+
+template <class T>
+class Normalized {
+public:
+ T value;
+
+ Normalized() : value(0) {}
+
+ explicit Normalized(float f)
+ : value(static_cast<T>(std::numeric_limits<T>::max() * util::clamp(f, 0.0f, 1.0f))) {
+ assert(f >= 0.0f);
+ assert(f <= 1.0f);
+ }
+
+ float denormalized() const {
+ return float(value) / std::numeric_limits<T>::max();
+ }
+};
+
+template <class T>
+bool operator==(const Normalized<T>& lhs, const Normalized<T>& rhs) {
+ return lhs.value == rhs.value;
+}
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp
index 33387e9d4e..fa0470796e 100644
--- a/src/mbgl/gl/program.hpp
+++ b/src/mbgl/gl/program.hpp
@@ -20,16 +20,14 @@ public:
using Attributes = As;
using Uniforms = Us;
- using Vertex = typename Attributes::Vertex;
using UniformValues = typename Uniforms::Values;
-
- static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+ using AttributeBindings = typename Attributes::Bindings;
Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource)
: vertexShader(context.createShader(ShaderType::Vertex, vertexSource)),
fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)),
program(context.createProgram(vertexShader, fragmentShader)),
- attributesState(Attributes::state(program)),
+ attributeLocations(Attributes::locations(program)),
uniformsState((context.linkProgram(program), Uniforms::state(program))) {}
template <class DrawMode>
@@ -39,22 +37,30 @@ public:
StencilMode stencilMode,
ColorMode colorMode,
UniformValues&& uniformValues,
- const VertexBuffer<Vertex>& vertexBuffer,
+ AttributeBindings&& attributeBindings,
const IndexBuffer<DrawMode>& indexBuffer,
const SegmentVector<Attributes>& segments) {
static_assert(std::is_same<Primitive, typename DrawMode::Primitive>::value, "incompatible draw mode");
- context.draw({
- std::move(drawMode),
- std::move(depthMode),
- std::move(stencilMode),
- std::move(colorMode),
- program,
- vertexBuffer.buffer,
- indexBuffer.buffer,
- segments,
- Uniforms::binder(uniformsState, std::move(uniformValues)),
- Attributes::binder(attributesState)
- });
+
+ context.setDrawMode(drawMode);
+ context.setDepthMode(depthMode);
+ context.setStencilMode(stencilMode);
+ context.setColorMode(colorMode);
+
+ context.program = program;
+
+ Uniforms::bind(uniformsState, std::move(uniformValues));
+
+ for (const auto& segment : segments) {
+ segment.bind(context,
+ indexBuffer.buffer,
+ attributeLocations,
+ attributeBindings);
+
+ context.draw(drawMode.primitiveType,
+ segment.indexOffset,
+ segment.indexLength);
+ }
}
private:
@@ -62,7 +68,7 @@ private:
UniqueShader fragmentShader;
UniqueProgram program;
- typename Attributes::State attributesState;
+ typename Attributes::Locations attributeLocations;
typename Uniforms::State uniformsState;
};
diff --git a/src/mbgl/gl/segment.cpp b/src/mbgl/gl/segment.cpp
new file mode 100644
index 0000000000..aabdc83cd4
--- /dev/null
+++ b/src/mbgl/gl/segment.cpp
@@ -0,0 +1,7 @@
+#include <mbgl/gl/segment.hpp>
+
+namespace mbgl {
+namespace gl {
+
+} // namespace gl
+} // namespace mbgl
diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp
index 8f74afd237..bd4926476f 100644
--- a/src/mbgl/gl/segment.hpp
+++ b/src/mbgl/gl/segment.hpp
@@ -1,12 +1,18 @@
#pragma once
+#include <mbgl/gl/context.hpp>
+#include <mbgl/gl/vertex_buffer.hpp>
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/logging.hpp>
+#include <mutex>
#include <cstddef>
+#include <vector>
namespace mbgl {
namespace gl {
+template <class Attributes>
class Segment {
public:
Segment(std::size_t vertexOffset_,
@@ -24,13 +30,46 @@ public:
std::size_t vertexLength;
std::size_t indexLength;
+ void bind(Context& context,
+ BufferID indexBuffer_,
+ const typename Attributes::Locations& attributeLocations,
+ const typename Attributes::Bindings& attributeBindings_) const {
+ if (context.supportsVertexArrays()) {
+ if (!vao) {
+ vao = context.createVertexArray();
+ context.vertexBuffer.setDirty();
+ }
+ context.vertexArrayObject = *vao;
+ if (indexBuffer != indexBuffer_) {
+ indexBuffer = indexBuffer_;
+ context.elementBuffer.setDirty();
+ context.elementBuffer = indexBuffer_;
+ }
+ } else {
+ // No VAO support. Force attributes to be rebound.
+ static std::once_flag reportedOnce;
+ std::call_once(reportedOnce, [] {
+ Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
+ });
+ context.elementBuffer = indexBuffer_;
+ variableBindings = {};
+ }
+
+ Attributes::bind(context,
+ attributeLocations,
+ variableBindings,
+ attributeBindings_,
+ vertexOffset);
+ }
+
private:
- friend class Context;
mutable optional<UniqueVertexArray> vao;
+ mutable optional<BufferID> indexBuffer;
+ mutable typename Attributes::VariableBindings variableBindings;
};
template <class Attributes>
-class SegmentVector : public std::vector<Segment> {
+class SegmentVector : public std::vector<Segment<Attributes>> {
public:
SegmentVector() = default;
};
diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp
index 577629d5d3..565ca5754f 100644
--- a/src/mbgl/gl/types.hpp
+++ b/src/mbgl/gl/types.hpp
@@ -34,16 +34,6 @@ enum class DataType : uint32_t {
Float = 0x1406
};
-template <typename T> struct DataTypeOf;
-
-template <> struct DataTypeOf<int8_t> : std::integral_constant<DataType, DataType::Byte> {};
-template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {};
-template <> struct DataTypeOf<int16_t> : std::integral_constant<DataType, DataType::Short> {};
-template <> struct DataTypeOf<uint16_t> : std::integral_constant<DataType, DataType::UnsignedShort> {};
-template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataType::Integer> {};
-template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {};
-template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {};
-
enum class RenderbufferType : uint32_t {
RGBA = 0x8058,
DepthStencil = 0x88F0,
diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp
index 726cd4fe10..92136b61c2 100644
--- a/src/mbgl/gl/uniform.hpp
+++ b/src/mbgl/gl/uniform.hpp
@@ -50,32 +50,49 @@ template <class Tag, class T, size_t N>
using UniformMatrix = Uniform<Tag, std::array<T, N*N>>;
#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \
- struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static auto name() { return #name_; } }
#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \
- struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static auto name() { return #name_; } }
#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \
- struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; }
+ struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static auto name() { return #name_; } }
UniformLocation uniformLocation(ProgramID, const char * name);
template <class... Us>
class Uniforms {
public:
+ using Types = TypeList<Us...>;
using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>;
using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>;
static State state(const ProgramID& id) {
- return State { { uniformLocation(id, Us::name) }... };
+ return State { { uniformLocation(id, Us::name()) }... };
}
- static std::function<void ()> binder(State& state, Values&& values_) {
- return [&state, values = std::move(values_)] () mutable {
- util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... });
- };
+ static void bind(State& state, Values&& values) {
+ util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... });
}
};
+
+namespace detail {
+
+template <class...>
+struct ConcatenateUniforms;
+
+template <class... As, class... Bs>
+struct ConcatenateUniforms<TypeList<As...>, TypeList<Bs...>> {
+ using Type = Uniforms<As..., Bs...>;
+};
+
+} // namespace detail
+
+template <class A, class B>
+using ConcatenateUniforms = typename detail::ConcatenateUniforms<
+ typename A::Types,
+ typename B::Types>::Type;
+
} // namespace gl
} // namespace mbgl
diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp
index 6215e56f21..6b6e11324f 100644
--- a/src/mbgl/gl/vertex_array.hpp
+++ b/src/mbgl/gl/vertex_array.hpp
@@ -11,4 +11,4 @@ extern ExtensionFunction<void(GLsizei n, const GLuint* arrays)> DeleteVertexArra
extern ExtensionFunction<void(GLsizei n, GLuint* arrays)> GenVertexArrays;
} // namespace gl
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp
index 5dd61d9156..f4dc1680bc 100644
--- a/src/mbgl/layout/symbol_feature.hpp
+++ b/src/mbgl/layout/symbol_feature.hpp
@@ -3,13 +3,25 @@
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/optional.hpp>
+#include <array>
#include <string>
namespace mbgl {
-class SymbolFeature {
+class SymbolFeature : public GeometryTileFeature {
public:
- FeatureType type;
+ SymbolFeature(std::unique_ptr<GeometryTileFeature> feature_) :
+ feature(std::move(feature_)),
+ geometry(feature->getGeometries()) // we need a mutable copy of the geometry for mergeLines()
+ {}
+
+ FeatureType getType() const override { return feature->getType(); }
+ optional<Value> getValue(const std::string& key) const override { return feature->getValue(key); };
+ std::unordered_map<std::string,Value> getProperties() const override { return feature->getProperties(); };
+ optional<FeatureIdentifier> getID() const override { return feature->getID(); };
+ GeometryCollection getGeometries() const override { return geometry; };
+
+ std::unique_ptr<GeometryTileFeature> feature;
GeometryCollection geometry;
optional<std::u16string> text;
optional<std::string> icon;
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index fafcc7c15d..d81783b2f6 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -6,29 +6,45 @@ namespace mbgl {
using namespace style;
SymbolInstance::SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
const SymbolLayoutProperties::Evaluated& layout, const bool addToBuffers, const uint32_t index_,
const float textBoxScale, const float textPadding, const SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, const SymbolPlacementType iconPlacement,
- const GlyphPositions& face, const IndexedSubfeature& indexedFeature) :
+ const GlyphPositions& face, const IndexedSubfeature& indexedFeature, const std::size_t featureIndex_) :
point(anchor.point),
index(index_),
- hasText(shapedText),
+ hasText(shapedTextOrientations.first || shapedTextOrientations.second),
hasIcon(shapedIcon),
- // Create the quads used for rendering the glyphs.
- glyphQuads(addToBuffers && shapedText ?
- getGlyphQuads(anchor, shapedText, textBoxScale, line, layout, textPlacement, face) :
- SymbolQuads()),
+ // Create the collision features that will be used to check whether this symbol instance can be placed
+ textCollisionFeature(line, anchor, shapedTextOrientations.second ?: shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature),
+ iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature),
+ featureIndex(featureIndex_) {
- // Create the quad used for rendering the icon.
- iconQuads(addToBuffers && shapedIcon ?
- getIconQuads(anchor, shapedIcon, line, layout, iconPlacement, shapedText) :
- SymbolQuads()),
+ // Create the quads used for rendering the icon and glyphs.
+ if (addToBuffers) {
+ if (shapedIcon) {
+ iconQuad = getIconQuad(anchor, shapedIcon, line, layout, iconPlacement, shapedTextOrientations.first);
+ }
+ if (shapedTextOrientations.first) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.first, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ if (shapedTextOrientations.second) {
+ auto quads = getGlyphQuads(anchor, shapedTextOrientations.second, textBoxScale, line, layout, textPlacement, face);
+ glyphQuads.insert(glyphQuads.end(), quads.begin(), quads.end());
+ }
+ }
- // Create the collision features that will be used to check whether this symbol instance can be placed
- textCollisionFeature(line, anchor, shapedText, textBoxScale, textPadding, textPlacement, indexedFeature),
- iconCollisionFeature(line, anchor, shapedIcon, iconBoxScale, iconPadding, iconPlacement, indexedFeature)
- {}
+ if (shapedTextOrientations.first && shapedTextOrientations.second) {
+ writingModes = WritingModeType::Horizontal | WritingModeType::Vertical;
+ } else if (shapedTextOrientations.first) {
+ writingModes = WritingModeType::Horizontal;
+ } else if (shapedTextOrientations.second) {
+ writingModes = WritingModeType::Vertical;
+ } else {
+ writingModes = WritingModeType::None;
+ }
+}
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 508c11a394..532a4d30d8 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/text/quads.hpp>
+#include <mbgl/text/glyph.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -12,20 +13,22 @@ class IndexedSubfeature;
class SymbolInstance {
public:
explicit SymbolInstance(Anchor& anchor, const GeometryCoordinates& line,
- const Shaping& shapedText, const PositionedIcon& shapedIcon,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations, const PositionedIcon& shapedIcon,
const style::SymbolLayoutProperties::Evaluated&, const bool inside, const uint32_t index,
const float textBoxScale, const float textPadding, style::SymbolPlacementType textPlacement,
const float iconBoxScale, const float iconPadding, style::SymbolPlacementType iconPlacement,
- const GlyphPositions& face, const IndexedSubfeature& indexedfeature);
+ const GlyphPositions& face, const IndexedSubfeature& indexedfeature, const std::size_t featureIndex);
Point<float> point;
uint32_t index;
bool hasText;
bool hasIcon;
SymbolQuads glyphQuads;
- SymbolQuads iconQuads;
+ optional<SymbolQuad> iconQuad;
CollisionFeature textCollisionFeature;
CollisionFeature iconCollisionFeature;
+ WritingModeType writingModes;
+ std::size_t featureIndex;
};
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index eaa0332995..3a2c082ad8 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -3,7 +3,9 @@
#include <mbgl/layout/clip_lines.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/style/layer.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/get_anchors.hpp>
@@ -15,6 +17,7 @@
#include <mbgl/util/std.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/string.hpp>
+#include <mbgl/util/i18n.hpp>
#include <mbgl/math/clamp.hpp>
#include <mbgl/math/minmax.hpp>
#include <mbgl/math/log2.hpp>
@@ -27,48 +30,82 @@ namespace mbgl {
using namespace style;
-SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling_,
- float zoom_,
- const MapMode mode_,
- const GeometryTileLayer& layer,
- const style::Filter& filter,
- style::SymbolLayoutProperties::Evaluated layout_,
- float textMaxSize_,
+SymbolLayout::SymbolLayout(const BucketParameters& parameters,
+ const std::vector<const Layer*>& layers,
+ const GeometryTileLayer& sourceLayer,
SpriteAtlas& spriteAtlas_)
- : layerIDs(std::move(layerIDs_)),
- sourceLayerName(std::move(sourceLayerName_)),
- overscaling(overscaling_),
- zoom(zoom_),
- mode(mode_),
- layout(std::move(layout_)),
- textMaxSize(textMaxSize_),
+ : sourceLayerName(sourceLayer.getName()),
+ bucketName(layers.at(0)->getID()),
+ overscaling(parameters.tileID.overscaleFactor()),
+ zoom(parameters.tileID.overscaledZ),
+ mode(parameters.mode),
spriteAtlas(spriteAtlas_),
- tileSize(util::tileSize * overscaling_),
+ tileSize(util::tileSize * overscaling),
tilePixelRatio(float(util::EXTENT) / tileSize) {
- const bool hasText = !layout.get<TextField>().empty() && !layout.get<TextFont>().empty();
+ const SymbolLayer::Impl& leader = *layers.at(0)->as<SymbolLayer>()->impl;
+
+ layout = leader.layout.evaluate(PropertyEvaluationParameters(zoom));
+
+ if (layout.get<IconRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<IconRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<IconRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ if (layout.get<TextRotationAlignment>() == AlignmentType::Auto) {
+ if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
+ layout.get<TextRotationAlignment>() = AlignmentType::Map;
+ } else {
+ layout.get<TextRotationAlignment>() = AlignmentType::Viewport;
+ }
+ }
+
+ // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
+ if (layout.get<TextPitchAlignment>() == AlignmentType::Auto) {
+ layout.get<TextPitchAlignment>() = layout.get<TextRotationAlignment>();
+ }
+
+ textMaxSize = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
+
+ layout.get<IconSize>() = leader.layout.evaluate<IconSize>(PropertyEvaluationParameters(zoom + 1));
+ layout.get<TextSize>() = leader.layout.evaluate<TextSize>(PropertyEvaluationParameters(zoom + 1));
+
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ const bool hasText = !layout.get<TextFont>().empty() && hasTextField;
+
const bool hasIcon = !layout.get<IconImage>().empty();
if (!hasText && !hasIcon) {
return;
}
- auto layerName = layer.getName();
+ for (const auto& layer : layers) {
+ layerPaintProperties.emplace(layer->getID(), std::make_pair(
+ layer->as<SymbolLayer>()->impl->iconPaintProperties(),
+ layer->as<SymbolLayer>()->impl->textPaintProperties()
+ ));
+ }
// Determine and load glyph ranges
- const size_t featureCount = layer.featureCount();
+ const size_t featureCount = sourceLayer.featureCount();
for (size_t i = 0; i < featureCount; ++i) {
- auto feature = layer.getFeature(i);
- if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
+ auto feature = sourceLayer.getFeature(i);
+ if (!leader.filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
continue;
+
+ SymbolFeature ft(std::move(feature));
- SymbolFeature ft;
ft.index = i;
- auto getValue = [&feature](const std::string& key) -> std::string {
- auto value = feature->getValue(key);
+ auto getValue = [&ft](const std::string& key) -> std::string {
+ auto value = ft.getValue(key);
if (!value)
return std::string();
if (value->is<std::string>())
@@ -83,13 +120,18 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
return util::toString(value->get<double>());
return "null";
};
-
+
if (hasText) {
- std::string u8string = util::replaceTokens(layout.get<TextField>(), getValue);
+ std::string u8string = layout.evaluate<TextField>(zoom, ft);
+ if (layout.get<TextField>().isConstant()) {
+ u8string = util::replaceTokens(u8string, getValue);
+ }
+
+ auto textTransform = layout.evaluate<TextTransform>(zoom, ft);
- if (layout.get<TextTransform>() == TextTransformType::Uppercase) {
+ if (textTransform == TextTransformType::Uppercase) {
u8string = platform::uppercase(u8string);
- } else if (layout.get<TextTransform>() == TextTransformType::Lowercase) {
+ } else if (textTransform == TextTransformType::Lowercase) {
u8string = platform::lowercase(u8string);
}
@@ -98,6 +140,9 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
// Loop through all characters of this text and collect unique codepoints.
for (char16_t chr : *ft.text) {
ranges.insert(getGlyphRange(chr));
+ if (char16_t verticalChr = util::i18n::verticalizePunctuation(chr)) {
+ ranges.insert(getGlyphRange(verticalChr));
+ }
}
}
@@ -106,8 +151,6 @@ SymbolLayout::SymbolLayout(std::vector<std::string> layerIDs_,
}
if (ft.text || ft.icon) {
- ft.type = feature->getType();
- ft.geometry = feature->getGeometries();
features.push_back(std::move(ft));
}
}
@@ -122,7 +165,12 @@ bool SymbolLayout::hasSymbolInstances() const {
}
bool SymbolLayout::canPrepare(GlyphAtlas& glyphAtlas) {
- if (!layout.get<TextField>().empty() && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
+ const bool hasTextField = layout.get<TextField>().match(
+ [&] (const std::string& s) { return !s.empty(); },
+ [&] (const auto&) { return true; }
+ );
+
+ if (hasTextField && !layout.get<TextFont>().empty() && !glyphAtlas.hasGlyphRanges(layout.get<TextFont>(), ranges)) {
return false;
}
@@ -178,61 +226,83 @@ void SymbolLayout::prepare(uintptr_t tileUID,
auto glyphSet = glyphAtlas.getGlyphSet(layout.get<TextFont>());
- for (const auto& feature : features) {
+ const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
+ layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
+
+ for (auto it = features.begin(); it != features.end(); ++it) {
+ auto& feature = *it;
if (feature.geometry.empty()) continue;
- Shaping shapedText;
+ std::pair<Shaping, Shaping> shapedTextOrientations;
PositionedIcon shapedIcon;
GlyphPositions face;
// if feature has text, shape the text
if (feature.text) {
- shapedText = glyphSet->getShaping(
- /* string */ *feature.text,
- /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
- layout.get<TextMaxWidth>() * 24 : 0,
- /* lineHeight: ems */ layout.get<TextLineHeight>() * 24,
- /* horizontalAlign */ horizontalAlign,
- /* verticalAlign */ verticalAlign,
- /* justify */ justify,
- /* spacing: ems */ layout.get<TextLetterSpacing>() * 24,
- /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
- /* bidirectional algorithm object */ bidi);
-
- // Add the glyphs we need for this label to the glyph atlas.
- if (shapedText) {
- glyphAtlas.addGlyphs(tileUID, *feature.text, layout.get<TextFont>(), **glyphSet, face);
+ auto getShaping = [&] (const std::u16string& text, WritingModeType writingMode) {
+ const float oneEm = 24.0f;
+ const Shaping result = glyphSet->getShaping(
+ /* string */ text,
+ /* maxWidth: ems */ layout.get<SymbolPlacement>() != SymbolPlacementType::Line ?
+ layout.get<TextMaxWidth>() * oneEm : 0,
+ /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm,
+ /* horizontalAlign */ horizontalAlign,
+ /* verticalAlign */ verticalAlign,
+ /* justify */ justify,
+ /* spacing: ems */ layout.get<TextLetterSpacing>() * oneEm,
+ /* translate */ Point<float>(layout.get<TextOffset>()[0], layout.get<TextOffset>()[1]),
+ /* verticalHeight */ oneEm,
+ /* writingMode */ writingMode,
+ /* bidirectional algorithm object */ bidi);
+
+ // Add the glyphs we need for this label to the glyph atlas.
+ if (result) {
+ glyphAtlas.addGlyphs(tileUID, text, layout.get<TextFont>(), glyphSet, face);
+ }
+
+ return result;
+ };
+
+ shapedTextOrientations.first = getShaping(*feature.text, WritingModeType::Horizontal);
+
+ if (util::i18n::allowsVerticalWritingMode(*feature.text) && textAlongLine) {
+ shapedTextOrientations.second = getShaping(util::i18n::verticalizePunctuation(*feature.text), WritingModeType::Vertical);
}
}
// if feature has icon, get sprite atlas position
if (feature.icon) {
- auto image = spriteAtlas.getImage(*feature.icon, SpritePatternMode::Single);
+ auto image = spriteAtlas.getIcon(*feature.icon);
if (image) {
- shapedIcon = shapeIcon(*image, layout);
+ shapedIcon = shapeIcon(*image,
+ layout.evaluate<IconOffset>(zoom, feature),
+ layout.evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
assert((*image).spriteImage);
if ((*image).spriteImage->sdf) {
sdfIcons = true;
}
if ((*image).relativePixelRatio != 1.0f) {
iconsNeedLinear = true;
- } else if (layout.get<IconRotate>() != 0) {
+ } else if (layout.get<IconRotate>().constantOr(1) != 0) {
iconsNeedLinear = true;
}
}
}
// if either shapedText or icon position is present, add the feature
- if (shapedText || shapedIcon) {
- addFeature(feature, shapedText, shapedIcon, face);
+ if (shapedTextOrientations.first || shapedIcon) {
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, face);
}
+
+ feature.geometry.clear();
}
- features.clear();
+ compareText.clear();
}
-void SymbolLayout::addFeature(const SymbolFeature& feature,
- const Shaping& shapedText,
+void SymbolLayout::addFeature(const std::size_t index,
+ const SymbolFeature& feature,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face) {
const float minScale = 0.5f;
@@ -254,7 +324,7 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
? SymbolPlacementType::Point
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, layerIDs.at(0), symbolInstances.size()};
+ IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()};
auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) {
// https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers
@@ -277,11 +347,13 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
const bool addToBuffers = mode == MapMode::Still || withinPlus0;
- symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(),
+ symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout, addToBuffers, symbolInstances.size(),
textBoxScale, textPadding, textPlacement,
iconBoxScale, iconPadding, iconPlacement,
- face, indexedFeature);
+ face, indexedFeature, index);
};
+
+ const auto& type = feature.getType();
if (layout.get<SymbolPlacement>() == SymbolPlacementType::Line) {
auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT);
@@ -289,8 +361,8 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchors anchors = getAnchors(line,
symbolSpacing,
textMaxAngle,
- shapedText.left,
- shapedText.right,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).left,
+ (shapedTextOrientations.second ?: shapedTextOrientations.first).right,
shapedIcon.left,
shapedIcon.right,
glyphSize,
@@ -298,12 +370,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
overscaling);
for (auto& anchor : anchors) {
- if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) {
+ if (!feature.text || !anchorIsTooClose(*feature.text, textRepeatDistance, anchor)) {
addSymbolInstance(line, anchor);
}
}
}
- } else if (feature.type == FeatureType::Polygon) {
+ } else if (type == FeatureType::Polygon) {
for (const auto& polygon : classifyRings(feature.geometry)) {
Polygon<double> poly;
for (const auto& ring : polygon) {
@@ -319,12 +391,12 @@ void SymbolLayout::addFeature(const SymbolFeature& feature,
Anchor anchor(poi.x, poi.y, 0, minScale);
addSymbolInstance(polygon[0], anchor);
}
- } else if (feature.type == FeatureType::LineString) {
+ } else if (type == FeatureType::LineString) {
for (const auto& line : feature.geometry) {
Anchor anchor(line[0].x, line[0].y, 0, minScale);
addSymbolInstance(line, anchor);
}
- } else if (feature.type == FeatureType::Point) {
+ } else if (type == FeatureType::Point) {
for (const auto& points : feature.geometry) {
for (const auto& point : points) {
Anchor anchor(point.x, point.y, 0, minScale);
@@ -350,7 +422,7 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
}
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
- auto bucket = std::make_unique<SymbolBucket>(mode, layout, sdfIcons, iconsNeedLinear);
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, zoom, sdfIcons, iconsNeedLinear);
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
@@ -365,6 +437,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
+ const bool keepUpright = layout.get<TextKeepUpright>();
+
// Sort symbols by their y position on the canvas so that they lower symbols
// are drawn on top of higher symbols.
// Don't sort symbols that won't overlap because it isn't necessary and
@@ -416,22 +490,32 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
// Insert final placement into collision tree and add glyphs/icons to buffers
if (hasText) {
+ const float placementZoom = util::max(util::log2(glyphScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale, layout.get<TextIgnorePlacement>());
if (glyphScale < collisionTile.maxScale) {
- addSymbols(
- bucket->text, symbolInstance.glyphQuads, glyphScale,
- layout.get<TextKeepUpright>(), textPlacement, collisionTile.config.angle);
+ for (const auto& symbol : symbolInstance.glyphQuads) {
+ addSymbol(
+ bucket->text, symbol, placementZoom,
+ keepUpright, textPlacement, collisionTile.config.angle, symbolInstance.writingModes);
+ }
}
}
if (hasIcon) {
+ const float placementZoom = util::max(util::log2(iconScale) + zoom, 0.0f);
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale, layout.get<IconIgnorePlacement>());
- if (iconScale < collisionTile.maxScale) {
- addSymbols(
- bucket->icon, symbolInstance.iconQuads, iconScale,
- layout.get<IconKeepUpright>(), iconPlacement, collisionTile.config.angle);
+ if (iconScale < collisionTile.maxScale && symbolInstance.iconQuad) {
+ addSymbol(
+ bucket->icon, *symbolInstance.iconQuad, placementZoom,
+ keepUpright, iconPlacement, collisionTile.config.angle, symbolInstance.writingModes);
}
}
+
+ const auto& feature = features.at(symbolInstance.featureIndex);
+ for (auto& pair : bucket->paintPropertyBinders) {
+ pair.second.first.populateVertexVectors(feature, bucket->icon.vertices.vertexSize());
+ pair.second.second.populateVertexVectors(feature, bucket->text.vertices.vertexSize());
+ }
}
if (collisionTile.config.debug) {
@@ -442,67 +526,76 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
}
template <typename Buffer>
-void SymbolLayout::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float scale, const bool keepUpright, const style::SymbolPlacementType placement, const float placementAngle) {
+void SymbolLayout::addSymbol(Buffer& buffer,
+ const SymbolQuad& symbol,
+ const float placementZoom,
+ const bool keepUpright,
+ const style::SymbolPlacementType placement,
+ const float placementAngle,
+ const WritingModeType writingModes) {
constexpr const uint16_t vertexLength = 4;
- const float placementZoom = util::max(util::log2(scale) + zoom, 0.0f);
-
- for (const auto& symbol : symbols) {
- const auto &tl = symbol.tl;
- const auto &tr = symbol.tr;
- const auto &bl = symbol.bl;
- const auto &br = symbol.br;
- const auto &tex = symbol.tex;
-
- float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom);
- float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F);
- const auto &anchorPoint = symbol.anchorPoint;
-
- // drop upside down versions of glyphs
- const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
- if (keepUpright && placement == style::SymbolPlacementType::Line &&
- (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
- continue;
- }
- if (maxZoom <= minZoom)
- continue;
+ const auto &tl = symbol.tl;
+ const auto &tr = symbol.tr;
+ const auto &bl = symbol.bl;
+ const auto &br = symbol.br;
+ const auto &tex = symbol.tex;
+
+ float minZoom = util::max(zoom + util::log2(symbol.minScale), placementZoom);
+ float maxZoom = util::min(zoom + util::log2(symbol.maxScale), util::MAX_ZOOM_F);
+ const auto &anchorPoint = symbol.anchorPoint;
+
+ // drop incorrectly oriented glyphs
+ const float a = std::fmod(symbol.anchorAngle + placementAngle + M_PI, M_PI * 2);
+ if (writingModes & WritingModeType::Vertical) {
+ if (placement == style::SymbolPlacementType::Line && symbol.writingMode == WritingModeType::Vertical) {
+ if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 5 / 4) || a > (M_PI * 7 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line && (a <= (M_PI * 3 / 4) || a > (M_PI * 5 / 4)))
+ return;
+ } else if (keepUpright && placement == style::SymbolPlacementType::Line &&
+ (a <= M_PI / 2 || a > M_PI * 3 / 2)) {
+ return;
+ }
- // Lower min zoom so that while fading out the label
- // it can be shown outside of collision-free zoom levels
- if (minZoom == placementZoom) {
- minZoom = 0;
- }
+ if (maxZoom <= minZoom)
+ return;
- if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
- buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize());
- }
+ // Lower min zoom so that while fading out the label
+ // it can be shown outside of collision-free zoom levels
+ if (minZoom == placementZoom) {
+ minZoom = 0;
+ }
- // We're generating triangle fans, so we always start with the first
- // coordinate in this polygon.
- auto& segment = buffer.segments.back();
- assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
- uint16_t index = segment.vertexLength;
-
- // Encode angle of glyph
- uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
-
- // coordinates (2 triangles)
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle));
- buffer.vertices.emplace_back(SymbolAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
- minZoom, maxZoom, placementZoom, glyphAngle));
-
- // add the two triangles, referencing the four coordinates we just inserted.
- buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
- buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
-
- segment.vertexLength += vertexLength;
- segment.indexLength += 6;
+ if (buffer.segments.empty() || buffer.segments.back().vertexLength + vertexLength > std::numeric_limits<uint16_t>::max()) {
+ buffer.segments.emplace_back(buffer.vertices.vertexSize(), buffer.triangles.indexSize());
}
+
+ // We're generating triangle fans, so we always start with the first
+ // coordinate in this polygon.
+ auto& segment = buffer.segments.back();
+ assert(segment.vertexLength <= std::numeric_limits<uint16_t>::max());
+ uint16_t index = segment.vertexLength;
+
+ // Encode angle of glyph
+ uint8_t glyphAngle = std::round((symbol.glyphAngle / (M_PI * 2)) * 256);
+
+ // coordinates (2 triangles)
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tl, tex.x, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, tr, tex.x + tex.w, tex.y,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, bl, tex.x, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+ buffer.vertices.emplace_back(SymbolLayoutAttributes::vertex(anchorPoint, br, tex.x + tex.w, tex.y + tex.h,
+ minZoom, maxZoom, placementZoom, glyphAngle));
+
+ // add the two triangles, referencing the four coordinates we just inserted.
+ buffer.triangles.emplace_back(index + 0, index + 1, index + 2);
+ buffer.triangles.emplace_back(index + 1, index + 2, index + 3);
+
+ segment.vertexLength += vertexLength;
+ segment.indexLength += 6;
}
void SymbolLayout::addToDebugBuffers(CollisionTile& collisionTile, SymbolBucket& bucket) {
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index c89b791ccc..491d0078da 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -5,6 +5,7 @@
#include <mbgl/layout/symbol_feature.hpp>
#include <mbgl/layout/symbol_instance.hpp>
#include <mbgl/text/bidi.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <memory>
#include <map>
@@ -20,6 +21,7 @@ class GlyphAtlas;
class SymbolBucket;
namespace style {
+class BucketParameters;
class Filter;
class Layer;
} // namespace style
@@ -28,15 +30,9 @@ struct Anchor;
class SymbolLayout {
public:
- SymbolLayout(std::vector<std::string> layerIDs_,
- std::string sourceLayerName_,
- uint32_t overscaling,
- float zoom,
- const MapMode,
+ SymbolLayout(const style::BucketParameters&,
+ const std::vector<const style::Layer*>&,
const GeometryTileLayer&,
- const style::Filter&,
- style::SymbolLayoutProperties::Evaluated,
- float textMaxSize,
SpriteAtlas&);
bool canPrepare(GlyphAtlas&);
@@ -56,12 +52,13 @@ public:
State state = Pending;
- const std::vector<std::string> layerIDs;
- const std::string sourceLayerName;
+ std::unordered_map<std::string,
+ std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>> layerPaintProperties;
private:
- void addFeature(const SymbolFeature&,
- const Shaping& shapedText,
+ void addFeature(const size_t,
+ const SymbolFeature&,
+ const std::pair<Shaping, Shaping>& shapedTextOrientations,
const PositionedIcon& shapedIcon,
const GlyphPositions& face);
@@ -72,14 +69,18 @@ private:
// Adds placed items to the buffer.
template <typename Buffer>
- void addSymbols(Buffer&, const SymbolQuads&, float scale,
- const bool keepUpright, const style::SymbolPlacementType, const float placementAngle);
+ void addSymbol(Buffer&, const SymbolQuad&, float scale,
+ const bool keepUpright, const style::SymbolPlacementType, const float placementAngle,
+ WritingModeType writingModes);
+ const std::string sourceLayerName;
+ const std::string bucketName;
const float overscaling;
const float zoom;
const MapMode mode;
- const style::SymbolLayoutProperties::Evaluated layout;
- const float textMaxSize;
+
+ style::SymbolLayoutProperties::Evaluated layout;
+ float textMaxSize;
SpriteAtlas& spriteAtlas;
@@ -92,7 +93,7 @@ private:
GlyphRangeSet ranges;
std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
-
+
BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
};
diff --git a/src/mbgl/map/backend_scope.cpp b/src/mbgl/map/backend_scope.cpp
new file mode 100644
index 0000000000..98775ceadb
--- /dev/null
+++ b/src/mbgl/map/backend_scope.cpp
@@ -0,0 +1,36 @@
+#include <mbgl/map/backend_scope.hpp>
+#include <mbgl/map/backend.hpp>
+#include <mbgl/util/thread_local.hpp>
+
+#include <cassert>
+
+namespace mbgl {
+
+static util::ThreadLocal<BackendScope> currentScope;
+
+BackendScope::BackendScope(Backend& backend_)
+ : priorScope(currentScope.get()),
+ nextScope(nullptr),
+ backend(backend_) {
+ if (priorScope) {
+ assert(priorScope->nextScope == nullptr);
+ priorScope->nextScope = this;
+ }
+ backend.activate();
+ currentScope.set(this);
+}
+
+BackendScope::~BackendScope() {
+ assert(nextScope == nullptr);
+ if (priorScope) {
+ priorScope->backend.activate();
+ currentScope.set(priorScope);
+ assert(priorScope->nextScope == this);
+ priorScope->nextScope = nullptr;
+ } else {
+ backend.deactivate();
+ currentScope.set(nullptr);
+ }
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index e9d4d9e247..857f088b62 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -2,6 +2,7 @@
#include <mbgl/map/camera.hpp>
#include <mbgl/map/view.hpp>
#include <mbgl/map/backend.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/transform.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
@@ -24,6 +25,7 @@
#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/actor/scheduler.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/util/string.hpp>
#include <mbgl/math/log2.hpp>
namespace mbgl {
@@ -314,10 +316,15 @@ void Map::Impl::render(View& view) {
contextMode,
debugOptions };
- painter->render(*style,
- frameData,
- view,
- annotationManager->getSpriteAtlas());
+ try {
+ painter->render(*style,
+ frameData,
+ view,
+ annotationManager->getSpriteAtlas());
+ } catch (...) {
+ Log::Error(Event::General, "Exception in render: %s", util::toString(std::current_exception()).c_str());
+ exit(1);
+ }
auto request = std::move(stillImageRequest);
request->callback(nullptr);
@@ -471,26 +478,26 @@ void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation)
#pragma mark - Position
-void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
+void Map::moveBy(const ScreenCoordinate& point, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.moveBy(point, duration);
+ impl->transform.moveBy(point, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
+ setLatLng(latLng, optional<ScreenCoordinate> {}, animation);
}
-void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLng(latLng, padding, duration);
+ impl->transform.setLatLng(latLng, padding, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLng(latLng, anchor, duration);
+ impl->transform.setLatLng(latLng, anchor, animation);
impl->onUpdate(Update::Repaint);
}
@@ -513,15 +520,15 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
#pragma mark - Scale
-void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.scaleBy(ds, anchor, duration);
+ impl->transform.scaleBy(ds, anchor, animation);
impl->onUpdate(Update::RecalculateStyle);
}
-void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setScale(scale, anchor, duration);
+ impl->transform.setScale(scale, anchor, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -529,14 +536,20 @@ double Map::getScale() const {
return impl->transform.getScale();
}
-void Map::setZoom(double zoom, const Duration& duration) {
+void Map::setZoom(double zoom, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setZoom(zoom, {}, duration);
+ setZoom(zoom, optional<EdgeInsets> {}, animation);
}
-void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setZoom(zoom, padding, duration);
+ impl->transform.setZoom(zoom, anchor, animation);
+ impl->onUpdate(Update::RecalculateStyle);
+}
+
+void Map::setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
+ impl->cameraMutated = true;
+ impl->transform.setZoom(zoom, padding, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -544,14 +557,14 @@ double Map::getZoom() const {
return impl->transform.getZoom();
}
-void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
+void Map::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setLatLngZoom(latLng, zoom, {}, duration);
+ setLatLngZoom(latLng, zoom, {}, animation);
}
-void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
+ impl->transform.setLatLngZoom(latLng, zoom, padding, animation);
impl->onUpdate(Update::RecalculateStyle);
}
@@ -661,26 +674,26 @@ Size Map::getSize() const {
#pragma mark - Rotation
-void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
+void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.rotateBy(first, second, duration);
+ impl->transform.rotateBy(first, second, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setBearing(double degrees, const Duration& duration) {
+void Map::setBearing(double degrees, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setBearing(degrees, EdgeInsets(), duration);
+ setBearing(degrees, EdgeInsets(), animation);
}
-void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
+ impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, animation);
impl->onUpdate(Update::Repaint);
}
-void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
+void Map::setBearing(double degrees, optional<EdgeInsets> padding, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
+ impl->transform.setAngle(-degrees * util::DEG2RAD, padding, animation);
impl->onUpdate(Update::Repaint);
}
@@ -688,22 +701,22 @@ double Map::getBearing() const {
return -impl->transform.getAngle() * util::RAD2DEG;
}
-void Map::resetNorth(const Duration& duration) {
+void Map::resetNorth(const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setAngle(0, duration);
+ impl->transform.setAngle(0, animation);
impl->onUpdate(Update::Repaint);
}
#pragma mark - Pitch
-void Map::setPitch(double pitch, const Duration& duration) {
+void Map::setPitch(double pitch, const AnimationOptions& animation) {
impl->cameraMutated = true;
- setPitch(pitch, {}, duration);
+ setPitch(pitch, {}, animation);
}
-void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
impl->cameraMutated = true;
- impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
+ impl->transform.setPitch(pitch * util::DEG2RAD, anchor, animation);
impl->onUpdate(Update::Repaint);
}
@@ -912,8 +925,6 @@ void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> i
impl->styleMutated = true;
impl->style->spriteAtlas->setSprite(name, std::move(image));
- impl->style->spriteAtlas->updateDirty();
-
impl->onUpdate(Update::Repaint);
}
@@ -924,8 +935,6 @@ void Map::removeImage(const std::string& name) {
impl->styleMutated = true;
impl->style->spriteAtlas->removeSprite(name);
- impl->style->spriteAtlas->updateDirty();
-
impl->onUpdate(Update::Repaint);
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index ba5e205301..eab9e97bc0 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -322,7 +322,7 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
#pragma mark - Position
-void Transform::moveBy(const ScreenCoordinate& offset, const Duration& duration) {
+void Transform::moveBy(const ScreenCoordinate& offset, const AnimationOptions& animation) {
ScreenCoordinate centerOffset = {
offset.x,
-offset.y,
@@ -331,22 +331,22 @@ void Transform::moveBy(const ScreenCoordinate& offset, const Duration& duration)
CameraOptions camera;
camera.center = state.screenCoordinateToLatLng(centerPoint);
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLng(const LatLng& latLng, const Duration& duration) {
- setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
+void Transform::setLatLng(const LatLng& latLng, const AnimationOptions& animation) {
+ setLatLng(latLng, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const AnimationOptions& animation) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
camera.padding = padding;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
@@ -358,21 +358,21 @@ void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> ancho
padding.right = state.size.width - anchor->x;
if (padding) camera.padding = padding;
}
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
- setLatLngZoom(latLng, zoom, EdgeInsets {}, duration);
+void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const AnimationOptions& animation) {
+ setLatLngZoom(latLng, zoom, EdgeInsets {}, animation);
}
-void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
if (!latLng || std::isnan(zoom)) return;
CameraOptions camera;
camera.center = latLng;
camera.padding = padding;
camera.zoom = zoom;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
@@ -394,26 +394,26 @@ ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) co
#pragma mark - Zoom
-void Transform::scaleBy(double ds, const Duration& duration) {
- scaleBy(ds, optional<ScreenCoordinate> {}, duration);
+void Transform::scaleBy(double ds, const AnimationOptions& animation) {
+ scaleBy(ds, optional<ScreenCoordinate> {}, animation);
}
-void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(ds)) return;
double scale = util::clamp(state.scale * ds, state.min_scale, state.max_scale);
- setScale(scale, anchor, duration);
+ setScale(scale, anchor, animation);
}
-void Transform::setZoom(double zoom, const Duration& duration) {
- setZoom(zoom, optional<ScreenCoordinate> {}, duration);
+void Transform::setZoom(double zoom, const AnimationOptions& animation) {
+ setZoom(zoom, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& duration) {
- setScale(state.zoomScale(zoom), anchor, duration);
+void Transform::setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
+ setScale(state.zoomScale(zoom), anchor, animation);
}
-void Transform::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
- setScale(state.zoomScale(zoom), padding, duration);
+void Transform::setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& animation) {
+ setScale(state.zoomScale(zoom), padding, animation);
}
double Transform::getZoom() const {
@@ -424,22 +424,22 @@ double Transform::getScale() const {
return state.scale;
}
-void Transform::setScale(double scale, const Duration& duration) {
- setScale(scale, optional<ScreenCoordinate> {}, duration);
+void Transform::setScale(double scale, const AnimationOptions& animation) {
+ setScale(scale, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(scale)) return;
CameraOptions camera;
camera.zoom = state.scaleZoom(scale);
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setScale(double scale, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setScale(double scale, optional<EdgeInsets> padding, const AnimationOptions& animation) {
optional<ScreenCoordinate> anchor;
if (padding) anchor = getScreenCoordinate(padding);
- setScale(scale, anchor, duration);
+ setScale(scale, anchor, animation);
}
void Transform::setMinZoom(const double minZoom) {
@@ -454,7 +454,7 @@ void Transform::setMaxZoom(const double maxZoom) {
#pragma mark - Angle
-void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
+void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
ScreenCoordinate center = getScreenCoordinate();
const ScreenCoordinate offset = first - center;
const double distance = std::sqrt(std::pow(2, offset.x) + std::pow(2, offset.y));
@@ -470,25 +470,25 @@ void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate&
CameraOptions camera;
camera.angle = state.angle + util::angle_between(first - center, second - center);
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setAngle(double angle, const Duration& duration) {
- setAngle(angle, optional<ScreenCoordinate> {}, duration);
+void Transform::setAngle(double angle, const AnimationOptions& animation) {
+ setAngle(angle, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(angle)) return;
CameraOptions camera;
camera.angle = angle;
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
-void Transform::setAngle(double angle, optional<EdgeInsets> padding, const Duration& duration) {
+void Transform::setAngle(double angle, optional<EdgeInsets> padding, const AnimationOptions& animation) {
optional<ScreenCoordinate> anchor;
if (padding && *padding) anchor = getScreenCoordinate(padding);
- setAngle(angle, anchor, duration);
+ setAngle(angle, anchor, animation);
}
double Transform::getAngle() const {
@@ -497,16 +497,16 @@ double Transform::getAngle() const {
#pragma mark - Pitch
-void Transform::setPitch(double pitch, const Duration& duration) {
- setPitch(pitch, optional<ScreenCoordinate> {}, duration);
+void Transform::setPitch(double pitch, const AnimationOptions& animation) {
+ setPitch(pitch, optional<ScreenCoordinate> {}, animation);
}
-void Transform::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+void Transform::setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& animation) {
if (std::isnan(pitch)) return;
CameraOptions camera;
camera.pitch = pitch;
camera.anchor = anchor;
- easeTo(camera, duration);
+ easeTo(camera, animation);
}
double Transform::getPitch() const {
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index febe71035d..66c9915715 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -44,12 +44,12 @@ public:
/** Pans the map by the given amount.
@param offset The distance to pan the map by, measured in pixels from
top to bottom and from left to right. */
- void moveBy(const ScreenCoordinate& offset, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<EdgeInsets>, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, optional<ScreenCoordinate>, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void moveBy(const ScreenCoordinate& offset, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<EdgeInsets>, const AnimationOptions& = {});
+ void setLatLng(const LatLng&, optional<ScreenCoordinate>, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, const AnimationOptions& = {});
+ void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const AnimationOptions& = {});
LatLng getLatLng(optional<EdgeInsets> = {}) const;
ScreenCoordinate getScreenCoordinate(optional<EdgeInsets> = {}) const;
@@ -57,36 +57,36 @@ public:
/** Scales the map, keeping the given point fixed within the view.
@param ds The difference in scale factors to scale the map by. */
- void scaleBy(double ds, const Duration& = Duration::zero());
+ void scaleBy(double ds, const AnimationOptions& = {});
/** Scales the map, keeping the given point fixed within the view.
@param ds The difference in scale factors to scale the map by.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void scaleBy(double ds, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the scale factor, keeping the given point fixed within the view.
@param scale The new scale factor. */
- void setScale(double scale, const Duration& = Duration::zero());
+ void setScale(double scale, const AnimationOptions& = {});
/** Sets the scale factor, keeping the given point fixed within the view.
@param scale The new scale factor.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setScale(double scale, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the scale factor, keeping the center point fixed within the inset view.
@param scale The new scale factor.
@param padding The viewport padding that affects the fixed center point. */
- void setScale(double scale, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setScale(double scale, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Sets the zoom level, keeping the given point fixed within the view.
@param zoom The new zoom level. */
- void setZoom(double zoom, const Duration& = Duration::zero());
+ void setZoom(double zoom, const AnimationOptions& = {});
/** Sets the zoom level, keeping the given point fixed within the view.
@param zoom The new zoom level.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the zoom level, keeping the center point fixed within the inset view.
@param zoom The new zoom level.
@param padding The viewport padding that affects the fixed center point. */
- void setZoom(double zoom, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Returns the zoom level. */
double getZoom() const;
/** Returns the scale factor. */
@@ -97,21 +97,21 @@ public:
// Angle
- void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& = Duration::zero());
+ void rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& = {});
/** Sets the angle of rotation.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north. */
- void setAngle(double angle, const Duration& = Duration::zero());
+ void setAngle(double angle, const AnimationOptions& = {});
/** Sets the angle of rotation, keeping the given point fixed within the view.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param anchor A point relative to the top-left corner of the view. */
- void setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
/** Sets the angle of rotation, keeping the center point fixed within the inset view.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param padding The viewport padding that affects the fixed center point. */
- void setAngle(double angle, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<EdgeInsets> padding, const AnimationOptions& = {});
/** Returns the angle of rotation.
@return The angle of rotation, measured in radians counterclockwise from
true north. */
@@ -121,12 +121,12 @@ public:
/** Sets the pitch angle.
@param angle The new pitch angle, measured in radians toward the
horizon. */
- void setPitch(double pitch, const Duration& = Duration::zero());
+ void setPitch(double pitch, const AnimationOptions& = {});
/** Sets the pitch angle, keeping the given point fixed within the view.
@param angle The new pitch angle, measured in radians toward the
horizon.
@param anchor A point relative to the top-left corner of the view. */
- void setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ void setPitch(double pitch, optional<ScreenCoordinate> anchor, const AnimationOptions& = {});
double getPitch() const;
// North Orientation
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index 38bbe89377..bb90f2c13c 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -1,23 +1,221 @@
#pragma once
#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+#include <mbgl/gl/normalization.hpp>
#include <cstdint>
namespace mbgl {
namespace attributes {
-// Attributes common to several shaders.
+// Layout attributes
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
-MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_offset);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);
template <std::size_t N>
-struct a_data : gl::Attribute<a_data<N>, uint8_t, N> {
- static constexpr auto name = "a_data";
+struct a_data : gl::Attribute<uint8_t, N> {
+ static auto name() { return "a_data"; }
};
+template <std::size_t N>
+struct a_offset : gl::Attribute<int16_t, N> {
+ static auto name() { return "a_offset"; }
+};
+
+// Paint attributes
+
+template <class Attr>
+struct Min : Attr {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_min");
+ return name.c_str();
+ }
+};
+
+template <class Attr>
+struct Max : Attr {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_max");
+ return name.c_str();
+ }
+};
+
+template <class Attr>
+struct InterpolationUniform : gl::UniformScalar<InterpolationUniform<Attr>, float> {
+ static auto name() {
+ static const std::string name = Attr::name() + std::string("_t");
+ return name.c_str();
+ }
+};
+
+struct a_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+// used in the symbol sdf shader
+struct a_fill_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_fill_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+// used in the symbol sdf shader
+struct a_halo_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_halo_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_stroke_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_stroke_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_outline_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+ static auto name() { return "a_outline_color"; }
+
+ static Value value(const Color& color) {
+ return {{
+ gl::Normalized<uint8_t>(color.r),
+ gl::Normalized<uint8_t>(color.g),
+ gl::Normalized<uint8_t>(color.b),
+ gl::Normalized<uint8_t>(color.a)
+ }};
+ }
+};
+
+struct a_opacity : gl::Attribute<gl::Normalized<uint8_t>, 1> {
+ static auto name() { return "a_opacity"; }
+
+ static Value value(float opacity) {
+ return {{ gl::Normalized<uint8_t>(opacity) }};
+ }
+};
+
+struct a_stroke_opacity : gl::Attribute<gl::Normalized<uint8_t>, 1> {
+ static auto name() { return "a_stroke_opacity"; }
+
+ static Value value(float opacity) {
+ return {{ gl::Normalized<uint8_t>(opacity) }};
+ }
+};
+
+struct a_blur : gl::Attribute<float, 1> {
+ static auto name() { return "a_blur"; }
+
+ static Value value(float blur) {
+ return {{ blur }};
+ }
+};
+
+struct a_radius : gl::Attribute<float, 1> {
+ static auto name() { return "a_radius"; }
+
+ static Value value(float radius) {
+ return {{ radius }};
+ }
+};
+
+struct a_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_height : gl::Attribute<float, 1> {
+ static auto name() { return "a_height"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_base : gl::Attribute<float, 1> {
+ static auto name() { return "a_base"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_gap_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_gapwidth"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_stroke_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_stroke_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+template <>
+struct a_offset<1> : gl::Attribute<float, 1> {
+ static auto name() { return "a_offset"; }
+
+ static Value value(float offset) {
+ return {{ offset }};
+ }
+};
+
+struct a_halo_width : gl::Attribute<float, 1> {
+ static auto name() { return "a_halo_width"; }
+
+ static Value value(float width) {
+ return {{ width }};
+ }
+};
+
+struct a_halo_blur : gl::Attribute<float, 1> {
+ static auto name() { return "a_halo_blur"; }
+
+ static Value value(float blur) {
+ return {{ blur }};
+ }
+};
+
+
+
} // namespace attributes
} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.cpp b/src/mbgl/programs/circle_program.cpp
index d6bc439feb..99b47dd5c0 100644
--- a/src/mbgl/programs/circle_program.cpp
+++ b/src/mbgl/programs/circle_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(CircleProgram::Vertex) == 4, "expected CircleVertex size");
+static_assert(sizeof(CircleLayoutVertex) == 4, "expected CircleLayoutVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp
index c9aea1d137..8f056048b1 100644
--- a/src/mbgl/programs/circle_program.hpp
+++ b/src/mbgl/programs/circle_program.hpp
@@ -3,37 +3,26 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/circle.hpp>
+#include <mbgl/shaders/circle.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/circle_layer_properties.hpp>
namespace mbgl {
namespace uniforms {
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius);
-MBGL_DEFINE_UNIFORM_SCALAR(Color, u_stroke_color);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_width);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_opacity);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_scale_with_map);
} // namespace uniforms
-using CircleAttributes = gl::Attributes<
- attributes::a_pos>;
-
class CircleProgram : public Program<
shaders::circle,
gl::Triangle,
- CircleAttributes,
+ gl::Attributes<
+ attributes::a_pos>,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
- uniforms::u_color,
- uniforms::u_radius,
- uniforms::u_blur,
- uniforms::u_stroke_color,
- uniforms::u_stroke_width,
- uniforms::u_stroke_opacity,
uniforms::u_scale_with_map,
- uniforms::u_extrude_scale>>
+ uniforms::u_extrude_scale>,
+ style::CirclePaintProperties>
{
public:
using Program::Program;
@@ -44,16 +33,17 @@ public:
* @param {number} ex extrude normal
* @param {number} ey extrude normal
*/
- static Vertex vertex(Point<int16_t> p, float ex, float ey) {
- return Vertex {
- {
+ static LayoutVertex vertex(Point<int16_t> p, float ex, float ey) {
+ return LayoutVertex {
+ {{
static_cast<int16_t>((p.x * 2) + ((ex + 1) / 2)),
static_cast<int16_t>((p.y * 2) + ((ey + 1) / 2))
- }
+ }}
};
}
};
-using CircleVertex = CircleProgram::Vertex;
+using CircleLayoutVertex = CircleProgram::LayoutVertex;
+using CircleAttributes = CircleProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.cpp b/src/mbgl/programs/collision_box_program.cpp
index d6a36e54a1..a3dc01ebe4 100644
--- a/src/mbgl/programs/collision_box_program.cpp
+++ b/src/mbgl/programs/collision_box_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(CollisionBoxProgram::Vertex) == 10, "expected CollisionBoxVertex size");
+static_assert(sizeof(CollisionBoxProgram::LayoutVertex) == 10, "expected CollisionBoxVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp
index 26e38419a4..78ed6aa0c9 100644
--- a/src/mbgl/programs/collision_box_program.hpp
+++ b/src/mbgl/programs/collision_box_program.hpp
@@ -3,7 +3,7 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/collision_box.hpp>
+#include <mbgl/shaders/collision_box.hpp>
#include <mbgl/util/geometry.hpp>
#include <cmath>
@@ -28,29 +28,30 @@ class CollisionBoxProgram : public Program<
uniforms::u_matrix,
uniforms::u_scale,
uniforms::u_zoom,
- uniforms::u_maxzoom>>
+ uniforms::u_maxzoom>,
+ style::PaintProperties<>>
{
public:
using Program::Program;
- static Vertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) {
- return Vertex {
- {
+ static LayoutVertex vertex(Point<float> a, Point<float> o, float maxzoom, float placementZoom) {
+ return LayoutVertex {
+ {{
static_cast<int16_t>(a.x),
static_cast<int16_t>(a.y)
- },
- {
+ }},
+ {{
static_cast<int16_t>(::round(o.x)),
static_cast<int16_t>(::round(o.y))
- },
- {
+ }},
+ {{
static_cast<uint8_t>(maxzoom * 10),
static_cast<uint8_t>(placementZoom * 10)
- }
+ }}
};
}
};
-using CollisionBoxVertex = CollisionBoxProgram::Vertex;
+using CollisionBoxVertex = CollisionBoxProgram::LayoutVertex;
} // namespace mbgl
diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp
index cd4e08b1bc..de1666b4a8 100644
--- a/src/mbgl/programs/debug_program.hpp
+++ b/src/mbgl/programs/debug_program.hpp
@@ -3,25 +3,25 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/debug.hpp>
+#include <mbgl/shaders/debug.hpp>
namespace mbgl {
-using DebugAttributes = gl::Attributes<
- attributes::a_pos>;
-
class DebugProgram : public Program<
shaders::debug,
gl::Line,
- DebugAttributes,
+ gl::Attributes<
+ attributes::a_pos>,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_color>>
+ uniforms::u_color>,
+ style::PaintProperties<>>
{
public:
using Program::Program;
};
-using DebugVertex = DebugProgram::Vertex;
+using DebugLayoutVertex = DebugProgram::LayoutVertex;
+using DebugAttributes = DebugProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp
index a8154d08f9..eebcffd2cb 100644
--- a/src/mbgl/programs/fill_program.cpp
+++ b/src/mbgl/programs/fill_program.cpp
@@ -8,14 +8,13 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(FillAttributes::Vertex) == 4, "expected FillVertex size");
+static_assert(sizeof(FillLayoutVertex) == 4, "expected FillLayoutVertex size");
FillPatternUniforms::Values
FillPatternUniforms::values(mat4 matrix,
- float opacity,
Size framebufferSize,
- const SpriteAtlasPosition& a,
- const SpriteAtlasPosition& b,
+ const SpriteAtlasElement& a,
+ const SpriteAtlasElement& b,
const Faded<std::string>& fading,
const UnwrappedTileID& tileID,
const TransformState& state)
@@ -26,7 +25,6 @@ FillPatternUniforms::values(mat4 matrix,
return FillPatternUniforms::Values {
uniforms::u_matrix::Value{ matrix },
- uniforms::u_opacity::Value{ opacity },
uniforms::u_world::Value{ framebufferSize },
uniforms::u_pattern_tl_a::Value{ a.tl },
uniforms::u_pattern_br_a::Value{ a.br },
diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp
index d885215c59..84ca2748d6 100644
--- a/src/mbgl/programs/fill_program.hpp
+++ b/src/mbgl/programs/fill_program.hpp
@@ -3,19 +3,20 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/fill.hpp>
-#include <mbgl/shader/fill_pattern.hpp>
-#include <mbgl/shader/fill_outline.hpp>
-#include <mbgl/shader/fill_outline_pattern.hpp>
+#include <mbgl/shaders/fill.hpp>
+#include <mbgl/shaders/fill_pattern.hpp>
+#include <mbgl/shaders/fill_outline.hpp>
+#include <mbgl/shaders/fill_outline_pattern.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/size.hpp>
+#include <mbgl/style/layers/fill_layer_properties.hpp>
#include <string>
namespace mbgl {
-class SpriteAtlasPosition;
+class SpriteAtlasElement;
class UnwrappedTileID;
class TransformState;
@@ -25,7 +26,6 @@ template <class> class Faded;
namespace uniforms {
MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world);
-MBGL_DEFINE_UNIFORM_SCALAR(Color, u_outline_color);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_a);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_b);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_tile_units_to_pixels);
@@ -33,32 +33,17 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower);
} // namespace uniforms
-struct FillAttributes : gl::Attributes<
+struct FillLayoutAttributes : gl::Attributes<
attributes::a_pos>
-{
- static Vertex vertex(Point<int16_t> p) {
- return Vertex {
- {
- p.x,
- p.y
- }
- };
- }
-};
-
-using FillVertex = FillAttributes::Vertex;
+{};
struct FillUniforms : gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
- uniforms::u_color,
- uniforms::u_outline_color,
uniforms::u_world>
{};
struct FillPatternUniforms : gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_world,
uniforms::u_pattern_tl_a,
uniforms::u_pattern_br_a,
@@ -75,10 +60,9 @@ struct FillPatternUniforms : gl::Uniforms<
uniforms::u_tile_units_to_pixels>
{
static Values values(mat4 matrix,
- float opacity,
Size framebufferSize,
- const SpriteAtlasPosition&,
- const SpriteAtlasPosition&,
+ const SpriteAtlasElement&,
+ const SpriteAtlasElement&,
const style::Faded<std::string>&,
const UnwrappedTileID&,
const TransformState&);
@@ -87,37 +71,57 @@ struct FillPatternUniforms : gl::Uniforms<
class FillProgram : public Program<
shaders::fill,
gl::Triangle,
- FillAttributes,
- FillUniforms>
+ FillLayoutAttributes,
+ FillUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
+
+ static LayoutVertex layoutVertex(Point<int16_t> p) {
+ return LayoutVertex {
+ {{
+ p.x,
+ p.y
+ }}
+ };
+ }
};
class FillPatternProgram : public Program<
shaders::fill_pattern,
gl::Triangle,
- FillAttributes,
- FillPatternUniforms>
+ FillLayoutAttributes,
+ FillPatternUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
class FillOutlineProgram : public Program<
shaders::fill_outline,
gl::Line,
- FillAttributes,
- FillUniforms>
+ FillLayoutAttributes,
+ FillUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
class FillOutlinePatternProgram : public Program<
shaders::fill_outline_pattern,
gl::Line,
- FillAttributes,
- FillPatternUniforms>
+ FillLayoutAttributes,
+ FillPatternUniforms,
+ style::FillPaintProperties>
{
+public:
using Program::Program;
};
+using FillLayoutVertex = FillProgram::LayoutVertex;
+using FillAttributes = FillProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp
index f7054d3398..d9778ba7ce 100644
--- a/src/mbgl/programs/line_program.cpp
+++ b/src/mbgl/programs/line_program.cpp
@@ -10,7 +10,7 @@ namespace mbgl {
using namespace style;
-static_assert(sizeof(LineAttributes::Vertex) == 8, "expected LineVertex size");
+static_assert(sizeof(LineLayoutVertex) == 8, "expected LineLayoutVertex size");
template <class Values, class...Args>
Values makeValues(const LinePaintProperties::Evaluated& properties,
@@ -25,11 +25,7 @@ Values makeValues(const LinePaintProperties::Evaluated& properties,
properties.get<LineTranslateAnchor>(),
state)
},
- uniforms::u_opacity::Value{ properties.get<LineOpacity>() },
uniforms::u_width::Value{ properties.get<LineWidth>() },
- uniforms::u_gapwidth::Value{ properties.get<LineGapWidth>() },
- uniforms::u_blur::Value{ properties.get<LineBlur>() },
- uniforms::u_offset::Value{ properties.get<LineOffset>() },
uniforms::u_ratio::Value{ 1.0f / tile.id.pixelsToTileUnits(1.0, state.getZoom()) },
uniforms::u_gl_units_to_pixels::Value{{{ 1.0f / pixelsToGLUnits[0], 1.0f / pixelsToGLUnits[1] }}},
std::forward<Args>(args)...
@@ -45,8 +41,7 @@ LineProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
properties,
tile,
state,
- pixelsToGLUnits,
- uniforms::u_color::Value{ properties.get<LineColor>() }
+ pixelsToGLUnits
);
}
@@ -78,7 +73,6 @@ LineSDFProgram::uniformValues(const LinePaintProperties::Evaluated& properties,
tile,
state,
pixelsToGLUnits,
- uniforms::u_color::Value{ properties.get<LineColor>() },
uniforms::u_patternscale_a::Value{ scaleA },
uniforms::u_patternscale_b::Value{ scaleB },
uniforms::u_tex_y_a::Value{ posA.y },
@@ -94,8 +88,8 @@ LinePatternProgram::uniformValues(const LinePaintProperties::Evaluated& properti
const RenderTile& tile,
const TransformState& state,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasPosition& posA,
- const SpriteAtlasPosition& posB) {
+ const SpriteAtlasElement& posA,
+ const SpriteAtlasElement& posB) {
std::array<float, 2> sizeA {{
tile.id.pixelsToTileUnits(posA.size[0] * properties.get<LinePattern>().fromScale, state.getIntegerZoom()),
posA.size[1]
diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp
index 9b97cc47a9..842b4cc602 100644
--- a/src/mbgl/programs/line_program.hpp
+++ b/src/mbgl/programs/line_program.hpp
@@ -3,11 +3,11 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/line.hpp>
-#include <mbgl/shader/line_pattern.hpp>
-#include <mbgl/shader/line_sdf.hpp>
-#include <mbgl/style/layers/line_layer_properties.hpp>
+#include <mbgl/shaders/line.hpp>
+#include <mbgl/shaders/line_pattern.hpp>
+#include <mbgl/shaders/line_sdf.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/line_layer_properties.hpp>
#include <cmath>
@@ -16,13 +16,11 @@ namespace mbgl {
class RenderTile;
class TransformState;
class LinePatternPos;
-class SpriteAtlasPosition;
+class SpriteAtlasElement;
namespace uniforms {
MBGL_DEFINE_UNIFORM_SCALAR(float, u_ratio);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_width);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_a);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_tex_y_b);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_sdfgamma);
@@ -32,24 +30,39 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_b);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels);
} // namespace uniforms
-struct LineAttributes : gl::Attributes<
+struct LineLayoutAttributes : gl::Attributes<
attributes::a_pos,
attributes::a_data<4>>
+{};
+
+class LineProgram : public Program<
+ shaders::line,
+ gl::Triangle,
+ LineLayoutAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_width,
+ uniforms::u_ratio,
+ uniforms::u_gl_units_to_pixels>,
+ style::LinePaintProperties>
{
+public:
+ using Program::Program;
+
/*
* @param p vertex position
* @param e extrude normal
* @param t texture normal
* @param dir direction of the line cap (-1/0/1)
*/
- static Vertex vertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) {
- return Vertex {
- {
+ static LayoutVertex layoutVertex(Point<int16_t> p, Point<double> e, Point<bool> t, int8_t dir, int32_t linesofar = 0) {
+ return LayoutVertex {
+ {{
static_cast<int16_t>((p.x * 2) | t.x),
static_cast<int16_t>((p.y * 2) | t.y)
- },
- {
- // add 128 to store an byte in an unsigned byte
+ }},
+ {{
+ // add 128 to store a byte in an unsigned byte
static_cast<uint8_t>(::round(extrudeScale * e.x) + 128),
static_cast<uint8_t>(::round(extrudeScale * e.y) + 128),
@@ -65,7 +78,7 @@ struct LineAttributes : gl::Attributes<
// so we need to shift the linesofar.
static_cast<uint8_t>(((dir == 0 ? 0 : (dir < 0 ? -1 : 1 )) + 1) | ((linesofar & 0x3F) << 2)),
static_cast<uint8_t>(linesofar >> 6)
- }
+ }}
};
}
@@ -77,27 +90,6 @@ struct LineAttributes : gl::Attributes<
* the acute/bevelled line join.
*/
static const int8_t extrudeScale = 63;
-};
-
-using LineVertex = LineAttributes::Vertex;
-
-class LineProgram : public Program<
- shaders::line,
- gl::Triangle,
- LineAttributes,
- gl::Uniforms<
- uniforms::u_matrix,
- uniforms::u_opacity,
- uniforms::u_width,
- uniforms::u_gapwidth,
- uniforms::u_blur,
- uniforms::u_offset,
- uniforms::u_ratio,
- uniforms::u_gl_units_to_pixels,
- uniforms::u_color>>
-{
-public:
- using Program::Program;
static UniformValues uniformValues(const style::LinePaintProperties::Evaluated&,
const RenderTile&,
@@ -108,14 +100,10 @@ public:
class LinePatternProgram : public Program<
shaders::line_pattern,
gl::Triangle,
- LineAttributes,
+ LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_width,
- uniforms::u_gapwidth,
- uniforms::u_blur,
- uniforms::u_offset,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
uniforms::u_pattern_tl_a,
@@ -125,7 +113,8 @@ class LinePatternProgram : public Program<
uniforms::u_pattern_size_a,
uniforms::u_pattern_size_b,
uniforms::u_fade,
- uniforms::u_image>>
+ uniforms::u_image>,
+ style::LinePaintProperties>
{
public:
using Program::Program;
@@ -134,31 +123,27 @@ public:
const RenderTile&,
const TransformState&,
const std::array<float, 2>& pixelsToGLUnits,
- const SpriteAtlasPosition& posA,
- const SpriteAtlasPosition& posB);
+ const SpriteAtlasElement& posA,
+ const SpriteAtlasElement& posB);
};
class LineSDFProgram : public Program<
shaders::line_sdf,
gl::Triangle,
- LineAttributes,
+ LineLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_width,
- uniforms::u_gapwidth,
- uniforms::u_blur,
- uniforms::u_offset,
uniforms::u_ratio,
uniforms::u_gl_units_to_pixels,
- uniforms::u_color,
uniforms::u_patternscale_a,
uniforms::u_patternscale_b,
uniforms::u_tex_y_a,
uniforms::u_tex_y_b,
uniforms::u_mix,
uniforms::u_sdfgamma,
- uniforms::u_image>>
+ uniforms::u_image>,
+ style::LinePaintProperties>
{
public:
using Program::Program;
@@ -174,4 +159,7 @@ public:
float atlasWidth);
};
+using LineLayoutVertex = LineProgram::LayoutVertex;
+using LineAttributes = LineProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp
index e5aae24997..e75dbebf18 100644
--- a/src/mbgl/programs/program.hpp
+++ b/src/mbgl/programs/program.hpp
@@ -2,21 +2,40 @@
#include <mbgl/gl/program.hpp>
#include <mbgl/programs/program_parameters.hpp>
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/style/paint_property.hpp>
#include <sstream>
#include <cassert>
namespace mbgl {
-template <class Shaders, class Primitive, class Attributes, class Uniforms>
-class Program : public gl::Program<Primitive, Attributes, Uniforms> {
+template <class Shaders,
+ class Primitive,
+ class LayoutAttrs,
+ class Uniforms,
+ class PaintProperties>
+class Program {
public:
- using ParentType = gl::Program<Primitive, Attributes, Uniforms>;
+ using LayoutAttributes = LayoutAttrs;
+ using LayoutVertex = typename LayoutAttributes::Vertex;
+
+ using PaintPropertyBinders = typename PaintProperties::Binders;
+ using PaintAttributes = typename PaintPropertyBinders::Attributes;
+ using Attributes = gl::ConcatenateAttributes<LayoutAttributes, PaintAttributes>;
+
+ using UniformValues = typename Uniforms::Values;
+ using PaintUniforms = typename PaintPropertyBinders::Uniforms;
+ using AllUniforms = gl::ConcatenateUniforms<Uniforms, PaintUniforms>;
+
+ using ProgramType = gl::Program<Primitive, Attributes, AllUniforms>;
+
+ ProgramType program;
Program(gl::Context& context, const ProgramParameters& programParameters)
- : ParentType(context, vertexSource(programParameters), fragmentSource(programParameters))
+ : program(context, vertexSource(programParameters), fragmentSource(programParameters))
{}
-
+
static std::string pixelRatioDefine(const ProgramParameters& parameters) {
std::ostringstream pixelRatioSS;
pixelRatioSS.imbue(std::locale("C"));
@@ -38,6 +57,33 @@ public:
return pixelRatioDefine(parameters) + Shaders::vertexSource;
}
+ template <class DrawMode>
+ void draw(gl::Context& context,
+ DrawMode drawMode,
+ gl::DepthMode depthMode,
+ gl::StencilMode stencilMode,
+ gl::ColorMode colorMode,
+ UniformValues&& uniformValues,
+ const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
+ const gl::IndexBuffer<DrawMode>& indexBuffer,
+ const gl::SegmentVector<Attributes>& segments,
+ const PaintPropertyBinders& paintPropertyBinders,
+ const typename PaintProperties::Evaluated& currentProperties,
+ float currentZoom) {
+ program.draw(
+ context,
+ std::move(drawMode),
+ std::move(depthMode),
+ std::move(stencilMode),
+ std::move(colorMode),
+ uniformValues
+ .concat(paintPropertyBinders.uniformValues(currentZoom)),
+ LayoutAttributes::allVariableBindings(layoutVertexBuffer)
+ .concat(paintPropertyBinders.attributeBindings(currentProperties)),
+ indexBuffer,
+ segments
+ );
+ }
};
} // namespace mbgl
diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp
index dd71c2ce97..742c5a221b 100644
--- a/src/mbgl/programs/programs.hpp
+++ b/src/mbgl/programs/programs.hpp
@@ -40,8 +40,8 @@ public:
LinePatternProgram linePattern;
RasterProgram raster;
SymbolIconProgram symbolIcon;
- SymbolSDFProgram symbolIconSDF;
- SymbolSDFProgram symbolGlyph;
+ SymbolSDFIconProgram symbolIconSDF;
+ SymbolSDFTextProgram symbolGlyph;
DebugProgram debug;
CollisionBoxProgram collisionBox;
diff --git a/src/mbgl/programs/raster_program.cpp b/src/mbgl/programs/raster_program.cpp
index ebec4c68cc..6906903e6b 100644
--- a/src/mbgl/programs/raster_program.cpp
+++ b/src/mbgl/programs/raster_program.cpp
@@ -2,6 +2,6 @@
namespace mbgl {
-static_assert(sizeof(RasterProgram::Vertex) == 8, "expected RasterVertex size");
+static_assert(sizeof(RasterLayoutVertex) == 8, "expected RasterLayoutVertex size");
} // namespace mbgl
diff --git a/src/mbgl/programs/raster_program.hpp b/src/mbgl/programs/raster_program.hpp
index 9aa25cf90c..09cb94ac17 100644
--- a/src/mbgl/programs/raster_program.hpp
+++ b/src/mbgl/programs/raster_program.hpp
@@ -3,8 +3,9 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/raster.hpp>
+#include <mbgl/shaders/raster.hpp>
#include <mbgl/util/geometry.hpp>
+#include <mbgl/style/layers/raster_layer_properties.hpp>
namespace mbgl {
@@ -22,14 +23,12 @@ MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_spin_weights);
MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_tl_parent);
} // namespace uniforms
-using RasterAttributes = gl::Attributes<
- attributes::a_pos,
- attributes::a_texture_pos>;
-
class RasterProgram : public Program<
shaders::raster,
gl::Triangle,
- RasterAttributes,
+ gl::Attributes<
+ attributes::a_pos,
+ attributes::a_texture_pos>,
gl::Uniforms<
uniforms::u_matrix,
uniforms::u_image0,
@@ -43,25 +42,27 @@ class RasterProgram : public Program<
uniforms::u_spin_weights,
uniforms::u_buffer_scale,
uniforms::u_scale_parent,
- uniforms::u_tl_parent>>
+ uniforms::u_tl_parent>,
+ style::RasterPaintProperties>
{
public:
using Program::Program;
- static Vertex vertex(Point<int16_t> p, Point<uint16_t> t) {
- return Vertex {
- {
+ static LayoutVertex layoutVertex(Point<int16_t> p, Point<uint16_t> t) {
+ return LayoutVertex {
+ {{
p.x,
p.y
- },
- {
+ }},
+ {{
t.x,
t.y
- }
+ }}
};
}
};
-using RasterVertex = RasterProgram::Vertex;
+using RasterLayoutVertex = RasterProgram::LayoutVertex;
+using RasterAttributes = RasterProgram::Attributes;
} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp
index d609dada8d..19fe2bc2f6 100644
--- a/src/mbgl/programs/symbol_program.cpp
+++ b/src/mbgl/programs/symbol_program.cpp
@@ -2,12 +2,13 @@
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
+#include <mbgl/util/enum.hpp>
namespace mbgl {
using namespace style;
-static_assert(sizeof(SymbolAttributes::Vertex) == 16, "expected SymbolVertex size");
+static_assert(sizeof(SymbolLayoutVertex) == 16, "expected SymbolLayoutVertex size");
template <class Values, class...Args>
Values makeValues(const style::SymbolPropertyValues& values,
@@ -19,6 +20,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
std::array<float, 2> extrudeScale;
const float scale = values.paintSize / values.sdfScale;
+
if (values.pitchAlignment == AlignmentType::Map) {
extrudeScale.fill(tile.id.pixelsToTileUnits(1, state.getZoom()) * scale);
} else {
@@ -27,7 +29,7 @@ Values makeValues(const style::SymbolPropertyValues& values,
pixelsToGLUnits[1] * scale * state.getCameraToCenterDistance()
}};
}
-
+
// adjust min/max zooms for variable font sies
float zoomAdjust = std::log(values.paintSize / values.layoutSize) / std::log(2);
@@ -35,7 +37,6 @@ Values makeValues(const style::SymbolPropertyValues& values,
uniforms::u_matrix::Value{ tile.translatedMatrix(values.translate,
values.translateAnchor,
state) },
- uniforms::u_opacity::Value{ values.opacity },
uniforms::u_extrude_scale::Value{ extrudeScale },
uniforms::u_texsize::Value{ std::array<float, 2> {{ float(texsize.width) / 4, float(texsize.height) / 4 }} },
uniforms::u_zoom::Value{ float((state.getZoom() - zoomAdjust) * 10) },
@@ -62,84 +63,37 @@ SymbolIconProgram::uniformValues(const style::SymbolPropertyValues& values,
);
}
-static SymbolSDFProgram::UniformValues makeSDFValues(const style::SymbolPropertyValues& values,
- const Size& texsize,
- const std::array<float, 2>& pixelsToGLUnits,
- const RenderTile& tile,
- const TransformState& state,
- float pixelRatio,
- Color color,
- float buffer,
- float gammaAdjust)
-{
- // The default gamma value has to be adjust for the current pixelratio so that we're not
- // drawing blurry font on retina screens.
- const float gammaBase = 0.105 * values.sdfScale / values.paintSize / pixelRatio;
- const float gammaScale = (values.pitchAlignment == AlignmentType::Map
- ? 1.0 / std::cos(state.getPitch())
- : 1.0) / state.getCameraToCenterDistance();
-
- return makeValues<SymbolSDFProgram::UniformValues>(
- values,
- texsize,
- pixelsToGLUnits,
- tile,
- state,
- uniforms::u_color::Value{ color },
- uniforms::u_buffer::Value{ buffer },
- uniforms::u_gamma::Value{ (gammaBase + gammaAdjust) * gammaScale },
- uniforms::u_pitch::Value{ state.getPitch() },
- uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
- uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
- uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map }
- );
-}
-
-SymbolSDFProgram::UniformValues
-SymbolSDFProgram::haloUniformValues(const style::SymbolPropertyValues& values,
+template <class PaintProperties>
+typename SymbolSDFProgram<PaintProperties>::UniformValues SymbolSDFProgram<PaintProperties>::uniformValues(const style::SymbolPropertyValues& values,
const Size& texsize,
const std::array<float, 2>& pixelsToGLUnits,
const RenderTile& tile,
const TransformState& state,
- float pixelRatio)
+ const SymbolSDFPart part)
{
const float scale = values.paintSize / values.sdfScale;
- const float sdfPx = 8.0f;
- const float blurOffset = 1.19f;
- const float haloOffset = 6.0f;
-
- return makeSDFValues(
+
+ const float gammaScale = scale * (values.pitchAlignment == AlignmentType::Map
+ ? std::cos(state.getPitch())
+ : 1.0) * state.getCameraToCenterDistance();
+
+ return makeValues<SymbolSDFProgram<PaintProperties>::UniformValues>(
values,
texsize,
pixelsToGLUnits,
tile,
state,
- pixelRatio,
- values.haloColor,
- (haloOffset - values.haloWidth / scale) / sdfPx,
- values.haloBlur * blurOffset / scale / sdfPx
+ uniforms::u_font_scale::Value{ scale },
+ uniforms::u_gamma_scale::Value{ gammaScale },
+ uniforms::u_pitch::Value{ state.getPitch() },
+ uniforms::u_bearing::Value{ -1.0f * state.getAngle() },
+ uniforms::u_aspect_ratio::Value{ (state.getSize().width * 1.0f) / (state.getSize().height * 1.0f) },
+ uniforms::u_pitch_with_map::Value{ values.pitchAlignment == AlignmentType::Map },
+ uniforms::u_is_halo::Value{ part == SymbolSDFPart::Halo }
);
}
-SymbolSDFProgram::UniformValues
-SymbolSDFProgram::foregroundUniformValues(const style::SymbolPropertyValues& values,
- const Size& texsize,
- const std::array<float, 2>& pixelsToGLUnits,
- const RenderTile& tile,
- const TransformState& state,
- float pixelRatio)
-{
- return makeSDFValues(
- values,
- texsize,
- pixelsToGLUnits,
- tile,
- state,
- pixelRatio,
- values.color,
- (256.0f - 64.0f) / 256.0f,
- 0
- );
-}
+template class SymbolSDFProgram<style::IconPaintProperties>;
+template class SymbolSDFProgram<style::TextPaintProperties>;
} // namespace mbgl
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index be987551c0..0537c25a2c 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -3,10 +3,12 @@
#include <mbgl/programs/program.hpp>
#include <mbgl/programs/attributes.hpp>
#include <mbgl/programs/uniforms.hpp>
-#include <mbgl/shader/symbol_icon.hpp>
-#include <mbgl/shader/symbol_sdf.hpp>
+#include <mbgl/shaders/symbol_icon.hpp>
+#include <mbgl/shaders/symbol_sdf.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/size.hpp>
+#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <cmath>
#include <array>
@@ -26,14 +28,15 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_fadetexture);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer);
-MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma);
MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
+MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_font_scale);
+MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
} // namespace uniforms
-struct SymbolAttributes : gl::Attributes<
+struct SymbolLayoutAttributes : gl::Attributes<
attributes::a_pos,
- attributes::a_offset,
+ attributes::a_offset<2>,
attributes::a_texture_pos,
attributes::a_data<4>>
{
@@ -46,43 +49,41 @@ struct SymbolAttributes : gl::Attributes<
float labelminzoom,
uint8_t labelangle) {
return Vertex {
- {
+ {{
static_cast<int16_t>(a.x),
static_cast<int16_t>(a.y)
- },
- {
+ }},
+ {{
static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement
static_cast<int16_t>(::round(o.y * 64))
- },
- {
+ }},
+ {{
static_cast<uint16_t>(tx / 4),
static_cast<uint16_t>(ty / 4)
- },
- {
+ }},
+ {{
static_cast<uint8_t>(labelminzoom * 10), // 1/10 zoom levels: z16 == 160
static_cast<uint8_t>(labelangle),
static_cast<uint8_t>(minzoom * 10),
static_cast<uint8_t>(::fmin(maxzoom, 25) * 10)
- }
+ }}
};
}
};
-using SymbolVertex = SymbolAttributes::Vertex;
-
class SymbolIconProgram : public Program<
shaders::symbol_icon,
gl::Triangle,
- SymbolAttributes,
+ SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_extrude_scale,
uniforms::u_texsize,
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
- uniforms::u_fadetexture>>
+ uniforms::u_fadetexture>,
+ style::IconPaintProperties>
{
public:
using Program::Program;
@@ -94,43 +95,73 @@ public:
const TransformState&);
};
+enum class SymbolSDFPart {
+ Fill = 1,
+ Halo = 0
+};
+
+template <class PaintProperties>
class SymbolSDFProgram : public Program<
shaders::symbol_sdf,
gl::Triangle,
- SymbolAttributes,
+ SymbolLayoutAttributes,
gl::Uniforms<
uniforms::u_matrix,
- uniforms::u_opacity,
uniforms::u_extrude_scale,
uniforms::u_texsize,
uniforms::u_zoom,
uniforms::u_rotate_with_map,
uniforms::u_texture,
uniforms::u_fadetexture,
- uniforms::u_color,
- uniforms::u_buffer,
- uniforms::u_gamma,
+ uniforms::u_font_scale,
+ uniforms::u_gamma_scale,
uniforms::u_pitch,
uniforms::u_bearing,
uniforms::u_aspect_ratio,
- uniforms::u_pitch_with_map>>
+ uniforms::u_pitch_with_map,
+ uniforms::u_is_halo>,
+ PaintProperties>
{
public:
- using Program::Program;
+ using BaseProgram = Program<shaders::symbol_sdf,
+ gl::Triangle,
+ SymbolLayoutAttributes,
+ gl::Uniforms<
+ uniforms::u_matrix,
+ uniforms::u_extrude_scale,
+ uniforms::u_texsize,
+ uniforms::u_zoom,
+ uniforms::u_rotate_with_map,
+ uniforms::u_texture,
+ uniforms::u_fadetexture,
+ uniforms::u_font_scale,
+ uniforms::u_gamma_scale,
+ uniforms::u_pitch,
+ uniforms::u_bearing,
+ uniforms::u_aspect_ratio,
+ uniforms::u_pitch_with_map,
+ uniforms::u_is_halo>,
+ PaintProperties>;
+
+ using UniformValues = typename BaseProgram::UniformValues;
+
+
+
+ using BaseProgram::BaseProgram;
- static UniformValues haloUniformValues(const style::SymbolPropertyValues&,
- const Size& texsize,
- const std::array<float, 2>& pixelsToGLUnits,
- const RenderTile&,
- const TransformState&,
- float pixelRatio);
-
- static UniformValues foregroundUniformValues(const style::SymbolPropertyValues&,
- const Size& texsize,
- const std::array<float, 2>& pixelsToGLUnits,
- const RenderTile&,
- const TransformState&,
- float pixelRatio);
+ static UniformValues uniformValues(const style::SymbolPropertyValues&,
+ const Size& texsize,
+ const std::array<float, 2>& pixelsToGLUnits,
+ const RenderTile&,
+ const TransformState&,
+ const SymbolSDFPart);
};
+using SymbolSDFIconProgram = SymbolSDFProgram<style::IconPaintProperties>;
+using SymbolSDFTextProgram = SymbolSDFProgram<style::TextPaintProperties>;
+
+using SymbolLayoutVertex = SymbolLayoutAttributes::Vertex;
+using SymbolIconAttributes = SymbolIconProgram::Attributes;
+using SymbolTextAttributes = SymbolSDFTextProgram::Attributes;
+
} // namespace mbgl
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index 49619c14f7..294e50dd8c 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -2,6 +2,7 @@
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/tile/geometry_tile_data.hpp>
#include <atomic>
@@ -22,6 +23,10 @@ class Layer;
class Bucket : private util::noncopyable {
public:
Bucket() = default;
+ virtual ~Bucket() = default;
+
+ virtual void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) {};
// As long as this bucket has a Prepare render pass, this function is getting called. Typically,
// this only happens once when the bucket is being rendered for the first time.
@@ -31,8 +36,6 @@ public:
// once or twice (for Opaque and Transparent render passes).
virtual void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) = 0;
- virtual ~Bucket() = default;
-
virtual bool hasData() const = 0;
bool needsUpload() const {
diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp
index ba2285c4eb..6722d04497 100644
--- a/src/mbgl/renderer/circle_bucket.cpp
+++ b/src/mbgl/renderer/circle_bucket.cpp
@@ -1,26 +1,38 @@
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
-#include <mbgl/gl/context.hpp>
-
#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/circle_layer.hpp>
+#include <mbgl/style/layers/circle_layer_impl.hpp>
#include <mbgl/util/constants.hpp>
namespace mbgl {
using namespace style;
-CircleBucket::CircleBucket(MapMode mode_) : mode(mode_) {
+CircleBucket::CircleBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers)
+ : mode(parameters.mode) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ CircleProgram::PaintPropertyBinders(
+ layer->as<CircleLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
}
void CircleBucket::upload(gl::Context& context) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(triangles));
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
void CircleBucket::render(Painter& painter,
- PaintParameters& parameters,
+ PaintParameters& parameters,
const Layer& layer,
const RenderTile& tile) {
painter.renderCircle(parameters, *this, *layer.as<CircleLayer>(), tile);
@@ -30,10 +42,11 @@ bool CircleBucket::hasData() const {
return !segments.empty();
}
-void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
+void CircleBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometry) {
constexpr const uint16_t vertexLength = 4;
- for (auto& circle : geometryCollection) {
+ for (auto& circle : geometry) {
for(auto& point : circle) {
auto x = point.x;
auto y = point.y;
@@ -76,6 +89,10 @@ void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
segment.indexLength += 6;
}
}
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp
index af7041a238..412db53f65 100644
--- a/src/mbgl/renderer/circle_bucket.hpp
+++ b/src/mbgl/renderer/circle_bucket.hpp
@@ -7,26 +7,34 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/gl/segment.hpp>
#include <mbgl/programs/circle_program.hpp>
+#include <mbgl/style/layers/circle_layer_properties.hpp>
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class CircleBucket : public Bucket {
public:
- CircleBucket(const MapMode);
+ CircleBucket(const style::BucketParameters&, const std::vector<const style::Layer*>&);
+
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
+ bool hasData() const override;
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
- bool hasData() const override;
- void addGeometry(const GeometryCollection&);
-
- gl::VertexVector<CircleVertex> vertices;
+ gl::VertexVector<CircleLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<CircleAttributes> segments;
- optional<gl::VertexBuffer<CircleVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<CircleLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+ std::unordered_map<std::string, CircleProgram::PaintPropertyBinders> paintPropertyBinders;
+
const MapMode mode;
};
diff --git a/src/mbgl/renderer/debug_bucket.cpp b/src/mbgl/renderer/debug_bucket.cpp
index 167df4376f..2a514989cf 100644
--- a/src/mbgl/renderer/debug_bucket.cpp
+++ b/src/mbgl/renderer/debug_bucket.cpp
@@ -23,7 +23,7 @@ DebugBucket::DebugBucket(const OverscaledTileID& id,
expires(std::move(expires_)),
debugMode(debugMode_) {
- gl::VertexVector<FillVertex> vertices;
+ gl::VertexVector<FillLayoutVertex> vertices;
gl::IndexVector<gl::Lines> indices;
auto addText = [&] (const std::string& text, double left, double baseline, double scale) {
@@ -43,7 +43,7 @@ DebugBucket::DebugBucket(const OverscaledTileID& id,
int16_t(::round(baseline - glyph.data[j + 1] * scale))
};
- vertices.emplace_back(FillAttributes::vertex(p));
+ vertices.emplace_back(FillProgram::layoutVertex(p));
if (prev) {
indices.emplace_back(vertices.vertexSize() - 2,
diff --git a/src/mbgl/renderer/debug_bucket.hpp b/src/mbgl/renderer/debug_bucket.hpp
index 4676381789..756e58a6de 100644
--- a/src/mbgl/renderer/debug_bucket.hpp
+++ b/src/mbgl/renderer/debug_bucket.hpp
@@ -34,7 +34,7 @@ public:
const MapDebugOptions debugMode;
gl::SegmentVector<DebugAttributes> segments;
- optional<gl::VertexBuffer<DebugVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<DebugLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> indexBuffer;
};
diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp
index b89e982057..64efafb108 100644
--- a/src/mbgl/renderer/fill_bucket.cpp
+++ b/src/mbgl/renderer/fill_bucket.cpp
@@ -1,8 +1,9 @@
#include <mbgl/renderer/fill_bucket.hpp>
-#include <mbgl/style/layers/fill_layer.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/programs/fill_program.hpp>
-#include <mbgl/util/logging.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/fill_layer.hpp>
+#include <mbgl/style/layers/fill_layer_impl.hpp>
#include <mapbox/earcut.hpp>
@@ -26,7 +27,17 @@ using namespace style;
struct GeometryTooLongException : std::exception {};
-void FillBucket::addGeometry(const GeometryCollection& geometry) {
+FillBucket::FillBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ FillProgram::PaintPropertyBinders(
+ layer->as<FillLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
+}
+
+void FillBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometry) {
for (auto& polygon : classifyRings(geometry)) {
// Optimize polygons with many interior rings for earcut tesselation.
limitHoles(polygon, 500);
@@ -55,11 +66,11 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
assert(lineSegment.vertexLength <= std::numeric_limits<uint16_t>::max());
uint16_t lineIndex = lineSegment.vertexLength;
- vertices.emplace_back(FillAttributes::vertex(ring[0]));
+ vertices.emplace_back(FillProgram::layoutVertex(ring[0]));
lines.emplace_back(lineIndex + nVertices - 1, lineIndex);
for (uint32_t i = 1; i < nVertices; i++) {
- vertices.emplace_back(FillAttributes::vertex(ring[i]));
+ vertices.emplace_back(FillProgram::layoutVertex(ring[i]));
lines.emplace_back(lineIndex + i - 1, lineIndex + i);
}
@@ -89,6 +100,10 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) {
triangleSegment.vertexLength += totalVertices;
triangleSegment.indexLength += nIndicies;
}
+
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
}
void FillBucket::upload(gl::Context& context) {
@@ -96,7 +111,10 @@ void FillBucket::upload(gl::Context& context) {
lineIndexBuffer = context.createIndexBuffer(std::move(lines));
triangleIndexBuffer = context.createIndexBuffer(std::move(triangles));
- // From now on, we're going to render during the opaque and translucent pass.
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp
index edb1521c1d..b403e1053b 100644
--- a/src/mbgl/renderer/fill_bucket.hpp
+++ b/src/mbgl/renderer/fill_bucket.hpp
@@ -6,28 +6,38 @@
#include <mbgl/gl/index_buffer.hpp>
#include <mbgl/gl/segment.hpp>
#include <mbgl/programs/fill_program.hpp>
+#include <mbgl/style/layers/fill_layer_properties.hpp>
#include <vector>
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class FillBucket : public Bucket {
public:
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
+ FillBucket(const style::BucketParameters&, const std::vector<const style::Layer*>&);
+
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
bool hasData() const override;
- void addGeometry(const GeometryCollection&);
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
- gl::VertexVector<FillVertex> vertices;
+ gl::VertexVector<FillLayoutVertex> vertices;
gl::IndexVector<gl::Lines> lines;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<FillAttributes> lineSegments;
gl::SegmentVector<FillAttributes> triangleSegments;
- optional<gl::VertexBuffer<FillVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<FillLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Lines>> lineIndexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> triangleIndexBuffer;
+
+ std::unordered_map<std::string, FillProgram::PaintPropertyBinders> paintPropertyBinders;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index 1ee53d87b2..a933a9004a 100644
--- a/src/mbgl/renderer/frame_history.cpp
+++ b/src/mbgl/renderer/frame_history.cpp
@@ -8,7 +8,7 @@ namespace mbgl {
FrameHistory::FrameHistory() {
changeOpacities.fill(0);
- std::fill(opacities.data.get(), opacities.data.get() + opacities.bytes(), 0);
+ opacities.fill(0);
}
void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) {
diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp
index fffbd113ed..f2b11f5f41 100644
--- a/src/mbgl/renderer/frame_history.hpp
+++ b/src/mbgl/renderer/frame_history.hpp
@@ -26,7 +26,7 @@ public:
private:
std::array<TimePoint, 256> changeTimes;
std::array<uint8_t, 256> changeOpacities;
- const AlphaImage opacities{ { 256, 1 } };
+ AlphaImage opacities{ { 256, 1 } };
int16_t previousZoomIndex = 0;
TimePoint previousTime;
diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp
index 007060bd1b..50a70c0fd4 100644
--- a/src/mbgl/renderer/line_bucket.cpp
+++ b/src/mbgl/renderer/line_bucket.cpp
@@ -1,6 +1,8 @@
#include <mbgl/renderer/line_bucket.hpp>
-#include <mbgl/style/layers/line_layer.hpp>
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/style/layers/line_layer.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/layers/line_layer_impl.hpp>
#include <mbgl/util/math.hpp>
#include <mbgl/util/constants.hpp>
@@ -10,19 +12,29 @@ namespace mbgl {
using namespace style;
-LineBucket::LineBucket(uint32_t overscaling_) : overscaling(overscaling_) {
-}
-
-LineBucket::~LineBucket() {
- // Do not remove. header file only contains forward definitions to unique pointers.
+LineBucket::LineBucket(const BucketParameters& parameters,
+ const std::vector<const Layer*>& layers,
+ const style::LineLayoutProperties& layout_)
+ : layout(layout_.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ))),
+ overscaling(parameters.tileID.overscaleFactor()) {
+ for (const auto& layer : layers) {
+ paintPropertyBinders.emplace(layer->getID(),
+ LineProgram::PaintPropertyBinders(
+ layer->as<LineLayer>()->impl->paint.evaluated,
+ parameters.tileID.overscaledZ));
+ }
}
-void LineBucket::addGeometry(const GeometryCollection& geometryCollection) {
+void LineBucket::addFeature(const GeometryTileFeature& feature,
+ const GeometryCollection& geometryCollection) {
for (auto& line : geometryCollection) {
addGeometry(line);
}
-}
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.populateVertexVectors(feature, vertices.vertexSize());
+ }
+}
/*
* Sharp corners cause dashed lines to tilt because the distance along the line
@@ -139,7 +151,14 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
// Determine the normal of the join extrusion. It is the angle bisector
// of the segments between the previous line and the next line.
- Point<double> joinNormal = util::unit(*prevNormal + *nextNormal);
+ // In the case of 180° angles, the prev and next normals cancel each other out:
+ // prevNormal + nextNormal = (0, 0), its magnitude is 0, so the unit vector would be
+ // undefined. In that case, we're keeping the joinNormal at (0, 0), so that the cosHalfAngle
+ // below will also become 0 and miterLength will become Infinity.
+ Point<double> joinNormal = *prevNormal + *nextNormal;
+ if (joinNormal.x != 0 || joinNormal.y != 0) {
+ joinNormal = util::unit(joinNormal);
+ }
/* joinNormal prevNormal
* ↖ ↑
@@ -155,7 +174,8 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
// Find the cosine of the angle between the next and join normals
// using dot product. The inverse of that is the miter length.
const double cosHalfAngle = joinNormal.x * nextNormal->x + joinNormal.y * nextNormal->y;
- const double miterLength = cosHalfAngle != 0 ? 1 / cosHalfAngle: 1;
+ const double miterLength =
+ cosHalfAngle != 0 ? 1 / cosHalfAngle : std::numeric_limits<double>::infinity();
const bool isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevCoordinate && nextCoordinate;
@@ -189,7 +209,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
if (currentJoin == LineJoinType::Bevel) {
// The maximum extrude length is 128 / 63 = 2 times the width of the line
- // so if miterLength >= 2 we need to draw a different type of bevel where.
+ // so if miterLength >= 2 we need to draw a different type of bevel here.
if (miterLength > 2) {
currentJoin = LineJoinType::FlipBevel;
}
@@ -216,7 +236,7 @@ void LineBucket::addGeometry(const GeometryCoordinates& coordinates) {
if (miterLength > 100) {
// Almost parallel lines
- joinNormal = *nextNormal;
+ joinNormal = *nextNormal * -1.0;
} else {
const double direction = prevNormal->x * nextNormal->y - prevNormal->y * nextNormal->x > 0 ? -1 : 1;
const double bevelLength = miterLength * util::mag(*prevNormal + *nextNormal) /
@@ -375,7 +395,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
Point<double> extrude = normal;
if (endLeft)
extrude = extrude - (util::perp(normal) * endLeft);
- vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, { round, false }, endLeft, distance * LINE_DISTANCE_SCALE));
e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
@@ -386,7 +406,7 @@ void LineBucket::addCurrentVertex(const GeometryCoordinate& currentCoordinate,
extrude = normal * -1.0;
if (endRight)
extrude = extrude - (util::perp(normal) * endRight);
- vertices.emplace_back(LineAttributes::vertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(currentCoordinate, extrude, { round, true }, -endRight, distance * LINE_DISTANCE_SCALE));
e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
@@ -411,7 +431,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex,
std::size_t startVertex,
std::vector<TriangleElement>& triangleStore) {
Point<double> flippedExtrude = extrude * (lineTurnsLeft ? -1.0 : 1.0);
- vertices.emplace_back(LineAttributes::vertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE));
+ vertices.emplace_back(LineProgram::layoutVertex(currentVertex, flippedExtrude, { false, lineTurnsLeft }, 0, distance * LINE_DISTANCE_SCALE));
e3 = vertices.vertexSize() - 1 - startVertex;
if (e1 >= 0 && e2 >= 0) {
triangleStore.emplace_back(e1, e2, e3);
@@ -428,7 +448,10 @@ void LineBucket::upload(gl::Context& context) {
vertexBuffer = context.createVertexBuffer(std::move(vertices));
indexBuffer = context.createIndexBuffer(std::move(triangles));
- // From now on, we're only going to render during the translucent pass.
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp
index d11d78ff69..78293d75f9 100644
--- a/src/mbgl/renderer/line_bucket.hpp
+++ b/src/mbgl/renderer/line_bucket.hpp
@@ -12,28 +12,37 @@
namespace mbgl {
+namespace style {
+class BucketParameters;
+} // namespace style
+
class LineBucket : public Bucket {
public:
- LineBucket(uint32_t overscaling);
- ~LineBucket() override;
+ LineBucket(const style::BucketParameters&,
+ const std::vector<const style::Layer*>&,
+ const style::LineLayoutProperties&);
- void upload(gl::Context&) override;
- void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
+ void addFeature(const GeometryTileFeature&,
+ const GeometryCollection&) override;
bool hasData() const override;
- void addGeometry(const GeometryCollection&);
- void addGeometry(const GeometryCoordinates& line);
+ void upload(gl::Context&) override;
+ void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
style::LineLayoutProperties::Evaluated layout;
- gl::VertexVector<LineVertex> vertices;
+ gl::VertexVector<LineLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
gl::SegmentVector<LineAttributes> segments;
- optional<gl::VertexBuffer<LineVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<LineLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
+ std::unordered_map<std::string, LineProgram::PaintPropertyBinders> paintPropertyBinders;
+
private:
+ void addGeometry(const GeometryCoordinates& line);
+
struct TriangleElement {
TriangleElement(uint16_t a_, uint16_t b_, uint16_t c_) : a(a_), b(b_), c(c_) {}
uint16_t a, b, c;
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp
index 505007304d..27d24d14a9 100644
--- a/src/mbgl/renderer/painter.cpp
+++ b/src/mbgl/renderer/painter.cpp
@@ -42,12 +42,12 @@ namespace mbgl {
using namespace style;
-static gl::VertexVector<FillVertex> tileVertices() {
- gl::VertexVector<FillVertex> result;
- result.emplace_back(FillAttributes::vertex({ 0, 0 }));
- result.emplace_back(FillAttributes::vertex({ util::EXTENT, 0 }));
- result.emplace_back(FillAttributes::vertex({ 0, util::EXTENT }));
- result.emplace_back(FillAttributes::vertex({ util::EXTENT, util::EXTENT }));
+static gl::VertexVector<FillLayoutVertex> tileVertices() {
+ gl::VertexVector<FillLayoutVertex> result;
+ result.emplace_back(FillProgram::layoutVertex({ 0, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, 0 }));
+ result.emplace_back(FillProgram::layoutVertex({ 0, util::EXTENT }));
+ result.emplace_back(FillProgram::layoutVertex({ util::EXTENT, util::EXTENT }));
return result;
}
@@ -68,12 +68,12 @@ static gl::IndexVector<gl::LineStrip> tileLineStripIndices() {
return result;
}
-static gl::VertexVector<RasterVertex> rasterVertices() {
- gl::VertexVector<RasterVertex> result;
- result.emplace_back(RasterProgram::vertex({ 0, 0 }, { 0, 0 }));
- result.emplace_back(RasterProgram::vertex({ util::EXTENT, 0 }, { 32767, 0 }));
- result.emplace_back(RasterProgram::vertex({ 0, util::EXTENT }, { 0, 32767 }));
- result.emplace_back(RasterProgram::vertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }));
+static gl::VertexVector<RasterLayoutVertex> rasterVertices() {
+ gl::VertexVector<RasterLayoutVertex> result;
+ result.emplace_back(RasterProgram::layoutVertex({ 0, 0 }, { 0, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, 0 }, { 32767, 0 }));
+ result.emplace_back(RasterProgram::layoutVertex({ 0, util::EXTENT }, { 0, 32767 }));
+ result.emplace_back(RasterProgram::layoutVertex({ util::EXTENT, util::EXTENT }, { 32767, 32767 }));
return result;
}
@@ -94,7 +94,7 @@ Painter::Painter(gl::Context& context_, const TransformState& state_, float pixe
ProgramParameters programParameters{ pixelRatio, false };
programs = std::make_unique<Programs>(context, programParameters);
#ifndef NDEBUG
-
+
ProgramParameters programParametersOverdraw{ pixelRatio, true };
overdrawPrograms = std::make_unique<Programs>(context, programParametersOverdraw);
#endif
diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp
index dec7fa57fd..91f329a6eb 100644
--- a/src/mbgl/renderer/painter.hpp
+++ b/src/mbgl/renderer/painter.hpp
@@ -158,8 +158,8 @@ private:
std::unique_ptr<Programs> overdrawPrograms;
#endif
- gl::VertexBuffer<FillVertex> tileVertexBuffer;
- gl::VertexBuffer<RasterVertex> rasterVertexBuffer;
+ gl::VertexBuffer<FillLayoutVertex> tileVertexBuffer;
+ gl::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer;
gl::IndexBuffer<gl::Triangles> tileTriangleIndexBuffer;
gl::IndexBuffer<gl::LineStrip> tileBorderIndexBuffer;
diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp
index 4a3e41701d..4ac414335b 100644
--- a/src/mbgl/renderer/painter_background.cpp
+++ b/src/mbgl/renderer/painter_background.cpp
@@ -14,13 +14,18 @@ using namespace style;
void Painter::renderBackground(PaintParameters& parameters, const BackgroundLayer& layer) {
// Note that for bottommost layers without a pattern, the background color is drawn with
// glClear rather than this method.
- const BackgroundPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+ const BackgroundPaintProperties::Evaluated& background = layer.impl->paint.evaluated;
- if (!properties.get<BackgroundPattern>().to.empty()) {
- optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
- properties.get<BackgroundPattern>().from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
- properties.get<BackgroundPattern>().to, SpritePatternMode::Repeating);
+ style::FillPaintProperties::Evaluated properties;
+ properties.get<FillPattern>() = background.get<BackgroundPattern>();
+ properties.get<FillOpacity>() = { background.get<BackgroundOpacity>() };
+ properties.get<FillColor>() = { background.get<BackgroundColor>() };
+
+ const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
+ if (!background.get<BackgroundPattern>().to.empty()) {
+ optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(background.get<BackgroundPattern>().from);
+ optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(background.get<BackgroundPattern>().to);
if (!imagePosA || !imagePosB)
return;
@@ -36,17 +41,19 @@ void Painter::renderBackground(PaintParameters& parameters, const BackgroundLaye
colorModeForRenderPass(),
FillPatternUniforms::values(
matrixForTile(tileID),
- properties.get<BackgroundOpacity>(),
context.viewport.getCurrentValue().size,
*imagePosA,
*imagePosB,
- properties.get<BackgroundPattern>(),
+ background.get<BackgroundPattern>(),
tileID,
state
),
tileVertexBuffer,
tileTriangleIndexBuffer,
- tileTriangleSegments
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
} else {
@@ -59,14 +66,14 @@ void Painter::renderBackground(PaintParameters& parameters, const BackgroundLaye
colorModeForRenderPass(),
FillProgram::UniformValues {
uniforms::u_matrix::Value{ matrixForTile(tileID) },
- uniforms::u_opacity::Value{ properties.get<BackgroundOpacity>() },
- uniforms::u_color::Value{ properties.get<BackgroundColor>() },
- uniforms::u_outline_color::Value{ properties.get<BackgroundColor>() },
uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
},
tileVertexBuffer,
tileTriangleIndexBuffer,
- tileTriangleSegments
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
}
diff --git a/src/mbgl/renderer/painter_circle.cpp b/src/mbgl/renderer/painter_circle.cpp
index 966d58b59b..8d47e75f71 100644
--- a/src/mbgl/renderer/painter_circle.cpp
+++ b/src/mbgl/renderer/painter_circle.cpp
@@ -37,13 +37,6 @@ void Painter::renderCircle(PaintParameters& parameters,
properties.get<CircleTranslateAnchor>(),
state)
},
- uniforms::u_opacity::Value{ properties.get<CircleOpacity>() },
- uniforms::u_color::Value{ properties.get<CircleColor>() },
- uniforms::u_radius::Value{ properties.get<CircleRadius>() },
- uniforms::u_blur::Value{ properties.get<CircleBlur>() },
- uniforms::u_stroke_color::Value{ properties.get<CircleStrokeColor>() },
- uniforms::u_stroke_width::Value{ properties.get<CircleStrokeWidth>() },
- uniforms::u_stroke_opacity::Value{ properties.get<CircleStrokeOpacity>() },
uniforms::u_scale_with_map::Value{ scaleWithMap },
uniforms::u_extrude_scale::Value{ scaleWithMap
? std::array<float, 2> {{
@@ -54,7 +47,10 @@ void Painter::renderCircle(PaintParameters& parameters,
},
*bucket.vertexBuffer,
*bucket.indexBuffer,
- bucket.segments
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_clipping.cpp b/src/mbgl/renderer/painter_clipping.cpp
index a2529561fe..70df9837e8 100644
--- a/src/mbgl/renderer/painter_clipping.cpp
+++ b/src/mbgl/renderer/painter_clipping.cpp
@@ -6,6 +6,8 @@
namespace mbgl {
void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& clip) {
+ static const style::FillPaintProperties::Evaluated properties {};
+ static const FillProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
programs->fill.draw(
context,
gl::Triangles(),
@@ -21,14 +23,14 @@ void Painter::renderClippingMask(const UnwrappedTileID& tileID, const ClipID& cl
gl::ColorMode::disabled(),
FillProgram::UniformValues {
uniforms::u_matrix::Value{ matrixForTile(tileID) },
- uniforms::u_opacity::Value{ 0.0f },
- uniforms::u_color::Value{ Color {} },
- uniforms::u_outline_color::Value{ Color {} },
uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
},
tileVertexBuffer,
tileTriangleIndexBuffer,
- tileTriangleSegments
+ tileTriangleSegments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp
index 2b838dec0e..5b347884bf 100644
--- a/src/mbgl/renderer/painter_debug.cpp
+++ b/src/mbgl/renderer/painter_debug.cpp
@@ -12,12 +12,17 @@
namespace mbgl {
+using namespace style;
+
void Painter::renderTileDebug(const RenderTile& renderTile) {
if (frame.debugOptions == MapDebugOptions::NoDebug)
return;
MBGL_DEBUG_GROUP(std::string { "debug " } + util::toString(renderTile.id));
+ static const style::PaintProperties<>::Evaluated properties {};
+ static const DebugProgram::PaintPropertyBinders paintAttibuteData(properties, 0);
+
auto draw = [&] (Color color, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, auto drawMode) {
programs->debug.draw(
context,
@@ -31,7 +36,10 @@ void Painter::renderTileDebug(const RenderTile& renderTile) {
},
vertexBuffer,
indexBuffer,
- segments
+ segments,
+ paintAttibuteData,
+ properties,
+ state.getZoom()
);
};
diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp
index 356ccfc0b2..4276bd06ed 100644
--- a/src/mbgl/renderer/painter_fill.cpp
+++ b/src/mbgl/renderer/painter_fill.cpp
@@ -24,10 +24,8 @@ void Painter::renderFill(PaintParameters& parameters,
return;
}
- optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(
- properties.get<FillPattern>().from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(
- properties.get<FillPattern>().to, SpritePatternMode::Repeating);
+ optional<SpriteAtlasElement> imagePosA = spriteAtlas->getPattern(properties.get<FillPattern>().from);
+ optional<SpriteAtlasElement> imagePosB = spriteAtlas->getPattern(properties.get<FillPattern>().to);
if (!imagePosA || !imagePosB) {
return;
@@ -38,7 +36,6 @@ void Painter::renderFill(PaintParameters& parameters,
auto draw = [&] (uint8_t sublayer,
auto& program,
const auto& drawMode,
- const auto& vertexBuffer,
const auto& indexBuffer,
const auto& segments) {
program.draw(
@@ -51,7 +48,6 @@ void Painter::renderFill(PaintParameters& parameters,
tile.translatedMatrix(properties.get<FillTranslate>(),
properties.get<FillTranslateAnchor>(),
state),
- properties.get<FillOpacity>(),
context.viewport.getCurrentValue().size,
*imagePosA,
*imagePosB,
@@ -59,16 +55,18 @@ void Painter::renderFill(PaintParameters& parameters,
tile.id,
state
),
- vertexBuffer,
+ *bucket.vertexBuffer,
indexBuffer,
- segments
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
draw(0,
parameters.programs.fillPattern,
gl::Triangles(),
- *bucket.vertexBuffer,
*bucket.triangleIndexBuffer,
bucket.triangleSegments);
@@ -79,15 +77,12 @@ void Painter::renderFill(PaintParameters& parameters,
draw(2,
parameters.programs.fillOutlinePattern,
gl::Lines { 2.0f },
- *bucket.vertexBuffer,
*bucket.lineIndexBuffer,
bucket.lineSegments);
} else {
auto draw = [&] (uint8_t sublayer,
auto& program,
- Color outlineColor,
const auto& drawMode,
- const auto& vertexBuffer,
const auto& indexBuffer,
const auto& segments) {
program.draw(
@@ -97,38 +92,37 @@ void Painter::renderFill(PaintParameters& parameters,
stencilModeForClipping(tile.clip),
colorModeForRenderPass(),
FillProgram::UniformValues {
- uniforms::u_matrix::Value{ tile.translatedMatrix(properties.get<FillTranslate>(),
- properties.get<FillTranslateAnchor>(),
- state) },
- uniforms::u_opacity::Value{ properties.get<FillOpacity>() },
- uniforms::u_color::Value{ properties.get<FillColor>() },
- uniforms::u_outline_color::Value{ outlineColor },
+ uniforms::u_matrix::Value{
+ tile.translatedMatrix(properties.get<FillTranslate>(),
+ properties.get<FillTranslateAnchor>(),
+ state)
+ },
uniforms::u_world::Value{ context.viewport.getCurrentValue().size },
},
- vertexBuffer,
+ *bucket.vertexBuffer,
indexBuffer,
- segments
+ segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
if (properties.get<FillAntialias>() && !layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
draw(2,
parameters.programs.fillOutline,
- properties.get<FillOutlineColor>(),
gl::Lines { 2.0f },
- *bucket.vertexBuffer,
*bucket.lineIndexBuffer,
bucket.lineSegments);
}
// Only draw the fill when it's opaque and we're drawing opaque fragments,
// or when it's translucent and we're drawing translucent fragments.
- if ((properties.get<FillColor>().a >= 1.0f && properties.get<FillOpacity>() >= 1.0f) == (pass == RenderPass::Opaque)) {
+ if ((properties.get<FillColor>().constantOr(Color()).a >= 1.0f
+ && properties.get<FillOpacity>().constantOr(0) >= 1.0f) == (pass == RenderPass::Opaque)) {
draw(1,
parameters.programs.fill,
- properties.get<FillOutlineColor>(),
gl::Triangles(),
- *bucket.vertexBuffer,
*bucket.triangleIndexBuffer,
bucket.triangleSegments);
}
@@ -136,9 +130,7 @@ void Painter::renderFill(PaintParameters& parameters,
if (properties.get<FillAntialias>() && layer.impl->paint.unevaluated.get<FillOutlineColor>().isUndefined() && pass == RenderPass::Translucent) {
draw(2,
parameters.programs.fillOutline,
- properties.get<FillColor>(),
gl::Lines { 2.0f },
- *bucket.vertexBuffer,
*bucket.lineIndexBuffer,
bucket.lineSegments);
}
diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp
index 012746d2f2..4e19f841b1 100644
--- a/src/mbgl/renderer/painter_line.cpp
+++ b/src/mbgl/renderer/painter_line.cpp
@@ -33,7 +33,10 @@ void Painter::renderLine(PaintParameters& parameters,
std::move(uniformValues),
*bucket.vertexBuffer,
*bucket.indexBuffer,
- bucket.segments
+ bucket.segments,
+ bucket.paintPropertyBinders.at(layer.getID()),
+ properties,
+ state.getZoom()
);
};
@@ -58,10 +61,8 @@ void Painter::renderLine(PaintParameters& parameters,
lineAtlas->getSize().width));
} else if (!properties.get<LinePattern>().from.empty()) {
- optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(
- properties.get<LinePattern>().from, SpritePatternMode::Repeating);
- optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition(
- properties.get<LinePattern>().to, SpritePatternMode::Repeating);
+ optional<SpriteAtlasElement> posA = spriteAtlas->getPattern(properties.get<LinePattern>().from);
+ optional<SpriteAtlasElement> posB = spriteAtlas->getPattern(properties.get<LinePattern>().to);
if (!posA || !posB)
return;
diff --git a/src/mbgl/renderer/painter_raster.cpp b/src/mbgl/renderer/painter_raster.cpp
index dcf2644140..c216955db8 100644
--- a/src/mbgl/renderer/painter_raster.cpp
+++ b/src/mbgl/renderer/painter_raster.cpp
@@ -49,6 +49,7 @@ void Painter::renderRaster(PaintParameters& parameters,
return;
const RasterPaintProperties::Evaluated& properties = layer.impl->paint.evaluated;
+ const RasterProgram::PaintPropertyBinders paintAttributeData(properties, 0);
assert(bucket.texture);
context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear);
@@ -77,7 +78,10 @@ void Painter::renderRaster(PaintParameters& parameters,
},
rasterVertexBuffer,
tileTriangleIndexBuffer,
- rasterSegments
+ rasterSegments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
);
}
diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp
index 39075976a0..48c2e7ff66 100644
--- a/src/mbgl/renderer/painter_symbol.cpp
+++ b/src/mbgl/renderer/painter_symbol.cpp
@@ -33,7 +33,9 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto draw = [&] (auto& program,
auto&& uniformValues,
const auto& buffers,
- const SymbolPropertyValues& values_)
+ const SymbolPropertyValues& values_,
+ const auto& binders,
+ const auto& paintProperties)
{
// We clip symbols to their tile extent in still mode.
const bool needsClipping = frame.mapMode == MapMode::Still;
@@ -51,12 +53,16 @@ void Painter::renderSymbol(PaintParameters& parameters,
std::move(uniformValues),
*buffers.vertexBuffer,
*buffers.indexBuffer,
- buffers.segments
+ buffers.segments,
+ binders,
+ paintProperties,
+ state.getZoom()
);
};
if (bucket.hasIconData()) {
auto values = layer.impl->iconPropertyValues(layout);
+ auto paintPropertyValues = layer.impl->iconPaintProperties();
SpriteAtlas& atlas = *layer.impl->spriteAtlas;
const bool iconScaled = values.paintSize != 1.0f || frame.pixelRatio != atlas.getPixelRatio() || bucket.iconsNeedLinear;
@@ -66,24 +72,30 @@ void Painter::renderSymbol(PaintParameters& parameters,
const Size texsize = atlas.getSize();
if (bucket.sdfIcons) {
- if (values.hasHalo()) {
+ if (values.hasHalo) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
- if (values.hasForeground()) {
+ if (values.hasFill) {
draw(parameters.programs.symbolIconSDF,
- SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
} else {
draw(parameters.programs.symbolIcon,
SymbolIconProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state),
bucket.icon,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).first,
+ paintPropertyValues);
}
}
@@ -91,25 +103,33 @@ void Painter::renderSymbol(PaintParameters& parameters,
glyphAtlas->bind(context, 0);
auto values = layer.impl->textPropertyValues(layout);
+ auto paintPropertyValues = layer.impl->textPaintProperties();
const Size texsize = glyphAtlas->getSize();
- if (values.hasHalo()) {
+ if (values.hasHalo) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFProgram::haloUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Halo),
bucket.text,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
}
- if (values.hasForeground()) {
+ if (values.hasFill) {
draw(parameters.programs.symbolGlyph,
- SymbolSDFProgram::foregroundUniformValues(values, texsize, pixelsToGLUnits, tile, state, frame.pixelRatio),
+ SymbolSDFTextProgram::uniformValues(values, texsize, pixelsToGLUnits, tile, state, SymbolSDFPart::Fill),
bucket.text,
- values);
+ values,
+ bucket.paintPropertyBinders.at(layer.getID()).second,
+ paintPropertyValues);
}
}
if (bucket.hasCollisionBoxData()) {
+ static const style::PaintProperties<>::Evaluated properties {};
+ static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
+
programs->collisionBox.draw(
context,
gl::Lines { 1.0f },
@@ -124,7 +144,10 @@ void Painter::renderSymbol(PaintParameters& parameters,
},
*bucket.collisionBox.vertexBuffer,
*bucket.collisionBox.indexBuffer,
- bucket.collisionBox.segments
+ bucket.collisionBox.segments,
+ paintAttributeData,
+ properties,
+ state.getZoom()
);
}
}
diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp
index 0f2c89339f..fa4178dda1 100644
--- a/src/mbgl/renderer/symbol_bucket.cpp
+++ b/src/mbgl/renderer/symbol_bucket.cpp
@@ -1,19 +1,28 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
+#include <mbgl/style/layers/symbol_layer_impl.hpp>
namespace mbgl {
using namespace style;
-SymbolBucket::SymbolBucket(const MapMode mode_,
- style::SymbolLayoutProperties::Evaluated layout_,
+SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::Evaluated layout_,
+ const std::unordered_map<std::string, std::pair<
+ style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>& layerPaintProperties,
+ float zoom,
bool sdfIcons_,
bool iconsNeedLinear_)
- : mode(mode_),
- layout(std::move(layout_)),
+ : layout(std::move(layout_)),
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_) {
+ for (const auto& pair : layerPaintProperties) {
+ paintPropertyBinders.emplace(pair.first, std::make_pair(
+ SymbolIconProgram::PaintPropertyBinders(pair.second.first, zoom),
+ SymbolSDFTextProgram::PaintPropertyBinders(pair.second.second, zoom)
+ ));
+ }
}
void SymbolBucket::upload(gl::Context& context) {
@@ -32,6 +41,11 @@ void SymbolBucket::upload(gl::Context& context) {
collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines));
}
+ for (auto& pair : paintPropertyBinders) {
+ pair.second.first.upload(context);
+ pair.second.second.upload(context);
+ }
+
uploaded = true;
}
diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp
index d62a61aab7..dcf3f5f495 100644
--- a/src/mbgl/renderer/symbol_bucket.hpp
+++ b/src/mbgl/renderer/symbol_bucket.hpp
@@ -16,8 +16,9 @@ namespace mbgl {
class SymbolBucket : public Bucket {
public:
- SymbolBucket(const MapMode,
- style::SymbolLayoutProperties::Evaluated,
+ SymbolBucket(style::SymbolLayoutProperties::Evaluated,
+ const std::unordered_map<std::string, std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>&,
+ float zoom,
bool sdfIcons,
bool iconsNeedLinear);
@@ -28,26 +29,29 @@ public:
bool hasIconData() const;
bool hasCollisionBoxData() const;
- const MapMode mode;
const style::SymbolLayoutProperties::Evaluated layout;
const bool sdfIcons;
const bool iconsNeedLinear;
+ std::unordered_map<std::string, std::pair<
+ SymbolIconProgram::PaintPropertyBinders,
+ SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders;
+
struct TextBuffer {
- gl::VertexVector<SymbolVertex> vertices;
+ gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
- gl::SegmentVector<SymbolAttributes> segments;
+ gl::SegmentVector<SymbolTextAttributes> segments;
- optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} text;
struct IconBuffer {
- gl::VertexVector<SymbolVertex> vertices;
+ gl::VertexVector<SymbolLayoutVertex> vertices;
gl::IndexVector<gl::Triangles> triangles;
- gl::SegmentVector<SymbolAttributes> segments;
+ gl::SegmentVector<SymbolIconAttributes> segments;
- optional<gl::VertexBuffer<SymbolVertex>> vertexBuffer;
+ optional<gl::VertexBuffer<SymbolLayoutVertex>> vertexBuffer;
optional<gl::IndexBuffer<gl::Triangles>> indexBuffer;
} icon;
diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp
new file mode 100644
index 0000000000..592a883fb3
--- /dev/null
+++ b/src/mbgl/shaders/circle.cpp
@@ -0,0 +1,191 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/circle.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* circle::name = "circle";
+const char* circle::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform bool u_scale_with_map;
+uniform vec2 u_extrude_scale;
+
+attribute vec2 a_pos;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_radius_t;
+attribute mediump float a_radius_min;
+attribute mediump float a_radius_max;
+varying mediump float radius;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_stroke_color_t;
+attribute lowp vec4 a_stroke_color_min;
+attribute lowp vec4 a_stroke_color_max;
+varying lowp vec4 stroke_color;
+uniform lowp float a_stroke_width_t;
+attribute mediump float a_stroke_width_min;
+attribute mediump float a_stroke_width_max;
+varying mediump float stroke_width;
+uniform lowp float a_stroke_opacity_t;
+attribute lowp float a_stroke_opacity_min;
+attribute lowp float a_stroke_opacity_max;
+varying lowp float stroke_opacity;
+
+varying vec2 v_extrude;
+varying lowp float v_antialiasblur;
+
+void main(void) {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ radius = mix(a_radius_min, a_radius_max, a_radius_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ stroke_color = mix(a_stroke_color_min, a_stroke_color_max, a_stroke_color_t);
+ stroke_width = mix(a_stroke_width_min, a_stroke_width_max, a_stroke_width_t);
+ stroke_opacity = mix(a_stroke_opacity_min, a_stroke_opacity_max, a_stroke_opacity_t);
+
+ // unencode the extrusion vector that we snuck into the a_pos vector
+ v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
+
+ vec2 extrude = v_extrude * (radius + stroke_width) * u_extrude_scale;
+ // multiply a_pos by 0.5, since we had it * 2 in order to sneak
+ // in extrusion data
+ gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0, 1);
+
+ if (u_scale_with_map) {
+ gl_Position.xy += extrude;
+ } else {
+ gl_Position.xy += extrude * gl_Position.w;
+ }
+
+ // This is a minimum blur distance that serves as a faux-antialiasing for
+ // the circle. since blur is a ratio of the circle's size and the intent is
+ // to keep the blur at roughly 1px, the two are inversely related.
+ v_antialiasblur = 1.0 / DEVICE_PIXEL_RATIO / (radius + stroke_width);
+}
+
+)MBGL_SHADER";
+const char* circle::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying mediump float radius;
+varying lowp float blur;
+varying lowp float opacity;
+varying lowp vec4 stroke_color;
+varying mediump float stroke_width;
+varying lowp float stroke_opacity;
+
+varying vec2 v_extrude;
+varying lowp float v_antialiasblur;
+
+void main() {
+
+
+
+
+
+
+
+
+ float extrude_length = length(v_extrude);
+ float antialiased_blur = -max(blur, v_antialiasblur);
+
+ float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
+
+ float color_t = stroke_width < 0.01 ? 0.0 : smoothstep(
+ antialiased_blur,
+ 0.0,
+ extrude_length - radius / (radius + stroke_width)
+ );
+
+ gl_FragColor = opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/circle.hpp b/src/mbgl/shaders/circle.hpp
new file mode 100644
index 0000000000..d14b26b783
--- /dev/null
+++ b/src/mbgl/shaders/circle.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class circle {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp
new file mode 100644
index 0000000000..6f2b9f3824
--- /dev/null
+++ b/src/mbgl/shaders/collision_box.cpp
@@ -0,0 +1,128 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/collision_box.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* collision_box::name = "collision_box";
+const char* collision_box::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+attribute vec2 a_extrude;
+attribute vec2 a_data;
+
+uniform mat4 u_matrix;
+uniform float u_scale;
+
+varying float v_max_zoom;
+varying float v_placement_zoom;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos + a_extrude / u_scale, 0.0, 1.0);
+
+ v_max_zoom = a_data.x;
+ v_placement_zoom = a_data.y;
+}
+
+)MBGL_SHADER";
+const char* collision_box::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform float u_zoom;
+uniform float u_maxzoom;
+
+varying float v_max_zoom;
+varying float v_placement_zoom;
+
+void main() {
+
+ float alpha = 0.5;
+
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0) * alpha;
+
+ if (v_placement_zoom > u_zoom) {
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha;
+ }
+
+ if (u_zoom >= v_max_zoom) {
+ gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) * alpha * 0.25;
+ }
+
+ if (v_placement_zoom >= u_maxzoom) {
+ gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0) * alpha * 0.2;
+ }
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/collision_box.hpp b/src/mbgl/shaders/collision_box.hpp
new file mode 100644
index 0000000000..e0f70c7968
--- /dev/null
+++ b/src/mbgl/shaders/collision_box.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class collision_box {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/debug.cpp b/src/mbgl/shaders/debug.cpp
new file mode 100644
index 0000000000..2659b2ca79
--- /dev/null
+++ b/src/mbgl/shaders/debug.cpp
@@ -0,0 +1,100 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/debug.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* debug::name = "debug";
+const char* debug::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos, step(32767.0, a_pos.x), 1);
+}
+
+)MBGL_SHADER";
+const char* debug::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform lowp vec4 u_color;
+
+void main() {
+ gl_FragColor = u_color;
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/debug.hpp b/src/mbgl/shaders/debug.hpp
new file mode 100644
index 0000000000..207c7bf075
--- /dev/null
+++ b/src/mbgl/shaders/debug.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class debug {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp
new file mode 100644
index 0000000000..066adee447
--- /dev/null
+++ b/src/mbgl/shaders/fill.cpp
@@ -0,0 +1,120 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill::name = "fill";
+const char* fill::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+}
+
+)MBGL_SHADER";
+const char* fill::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying lowp float opacity;
+
+void main() {
+
+
+
+ gl_FragColor = color * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill.hpp b/src/mbgl/shaders/fill.hpp
new file mode 100644
index 0000000000..29fede7b55
--- /dev/null
+++ b/src/mbgl/shaders/fill.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp
new file mode 100644
index 0000000000..0f0f3806a9
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline.cpp
@@ -0,0 +1,128 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_outline.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_outline::name = "fill_outline";
+const char* fill_outline::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+
+uniform mat4 u_matrix;
+uniform vec2 u_world;
+
+varying vec2 v_pos;
+
+uniform lowp float a_outline_color_t;
+attribute lowp vec4 a_outline_color_min;
+attribute lowp vec4 a_outline_color_max;
+varying lowp vec4 outline_color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ outline_color = mix(a_outline_color_min, a_outline_color_max, a_outline_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+ v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;
+}
+
+)MBGL_SHADER";
+const char* fill_outline::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 outline_color;
+varying lowp float opacity;
+
+varying vec2 v_pos;
+
+void main() {
+
+
+
+ float dist = length(v_pos - gl_FragCoord.xy);
+ float alpha = smoothstep(1.0, 0.0, dist);
+ gl_FragColor = outline_color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline.hpp b/src/mbgl/shaders/fill_outline.hpp
new file mode 100644
index 0000000000..ef685e62fa
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_outline {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp
new file mode 100644
index 0000000000..3921a83e6b
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline_pattern.cpp
@@ -0,0 +1,156 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_outline_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_outline_pattern::name = "fill_outline_pattern";
+const char* fill_outline_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_world;
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pixel_coord_upper;
+uniform vec2 u_pixel_coord_lower;
+uniform float u_scale_a;
+uniform float u_scale_b;
+uniform float u_tile_units_to_pixels;
+
+attribute vec2 a_pos;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+varying vec2 v_pos;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+
+ v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
+ v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
+
+ v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;
+}
+
+)MBGL_SHADER";
+const char* fill_outline_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_mix;
+
+uniform sampler2D u_image;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+varying vec2 v_pos;
+
+varying lowp float opacity;
+
+void main() {
+
+
+ vec2 imagecoord = mod(v_pos_a, 1.0);
+ vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec4 color1 = texture2D(u_image, pos);
+
+ vec2 imagecoord_b = mod(v_pos_b, 1.0);
+ vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);
+ vec4 color2 = texture2D(u_image, pos2);
+
+ // find distance to outline for alpha interpolation
+
+ float dist = length(v_pos - gl_FragCoord.xy);
+ float alpha = smoothstep(1.0, 0.0, dist);
+
+
+ gl_FragColor = mix(color1, color2, u_mix) * alpha * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_outline_pattern.hpp b/src/mbgl/shaders/fill_outline_pattern.hpp
new file mode 100644
index 0000000000..e1c7a173f4
--- /dev/null
+++ b/src/mbgl/shaders/fill_outline_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_outline_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp
new file mode 100644
index 0000000000..822a0f7b8f
--- /dev/null
+++ b/src/mbgl/shaders/fill_pattern.cpp
@@ -0,0 +1,145 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/fill_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* fill_pattern::name = "fill_pattern";
+const char* fill_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pixel_coord_upper;
+uniform vec2 u_pixel_coord_lower;
+uniform float u_scale_a;
+uniform float u_scale_b;
+uniform float u_tile_units_to_pixels;
+
+attribute vec2 a_pos;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+
+ v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
+ v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
+}
+
+)MBGL_SHADER";
+const char* fill_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_mix;
+
+uniform sampler2D u_image;
+
+varying vec2 v_pos_a;
+varying vec2 v_pos_b;
+
+varying lowp float opacity;
+
+void main() {
+
+
+ vec2 imagecoord = mod(v_pos_a, 1.0);
+ vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord);
+ vec4 color1 = texture2D(u_image, pos);
+
+ vec2 imagecoord_b = mod(v_pos_b, 1.0);
+ vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b);
+ vec4 color2 = texture2D(u_image, pos2);
+
+ gl_FragColor = mix(color1, color2, u_mix) * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/fill_pattern.hpp b/src/mbgl/shaders/fill_pattern.hpp
new file mode 100644
index 0000000000..4d09519ed8
--- /dev/null
+++ b/src/mbgl/shaders/fill_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class fill_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
new file mode 100644
index 0000000000..59fa9f0cf2
--- /dev/null
+++ b/src/mbgl/shaders/line.cpp
@@ -0,0 +1,216 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line::name = "line";
+const char* line::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform mediump float u_width;
+uniform vec2 u_gl_units_to_pixels;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_gamma_scale;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist = outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+varying lowp vec4 color;
+varying lowp float blur;
+varying lowp float opacity;
+
+varying vec2 v_width2;
+varying vec2 v_normal;
+varying float v_gamma_scale;
+
+void main() {
+
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line.hpp b/src/mbgl/shaders/line.hpp
new file mode 100644
index 0000000000..c0d81e6202
--- /dev/null
+++ b/src/mbgl/shaders/line.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp
new file mode 100644
index 0000000000..7f2a31ee44
--- /dev/null
+++ b/src/mbgl/shaders/line_pattern.cpp
@@ -0,0 +1,233 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line_pattern.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line_pattern::name = "line_pattern";
+const char* line_pattern::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+// We scale the distance before adding it to the buffers so that we can store
+// long distances for long segments. Use this value to unscale the distance.
+#define LINE_DISTANCE_SCALE 2.0
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform mediump float u_width;
+uniform vec2 u_gl_units_to_pixels;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_linesofar;
+varying float v_gamma_scale;
+
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+
+void main() {
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+ float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist = outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_linesofar = a_linesofar;
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line_pattern::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform vec2 u_pattern_size_a;
+uniform vec2 u_pattern_size_b;
+uniform vec2 u_pattern_tl_a;
+uniform vec2 u_pattern_br_a;
+uniform vec2 u_pattern_tl_b;
+uniform vec2 u_pattern_br_b;
+uniform float u_fade;
+
+uniform sampler2D u_image;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying float v_linesofar;
+varying float v_gamma_scale;
+
+varying lowp float blur;
+varying lowp float opacity;
+
+void main() {
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0);
+ float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0);
+ float y_a = 0.5 + (v_normal.y * v_width2.s / u_pattern_size_a.y);
+ float y_b = 0.5 + (v_normal.y * v_width2.s / u_pattern_size_b.y);
+ vec2 pos_a = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a));
+ vec2 pos_b = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b));
+
+ vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade);
+
+ gl_FragColor = color * alpha * opacity;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_pattern.hpp b/src/mbgl/shaders/line_pattern.hpp
new file mode 100644
index 0000000000..0394e83fe0
--- /dev/null
+++ b/src/mbgl/shaders/line_pattern.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line_pattern {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp
new file mode 100644
index 0000000000..011c1c3738
--- /dev/null
+++ b/src/mbgl/shaders/line_sdf.cpp
@@ -0,0 +1,239 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/line_sdf.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* line_sdf::name = "line_sdf";
+const char* line_sdf::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+// floor(127 / 2) == 63.0
+// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is
+// stored in a byte (-128..127). we scale regular normals up to length 63, but
+// there are also "special" normals that have a bigger length (of up to 126 in
+// this case).
+// #define scale 63.0
+#define scale 0.015873016
+
+// We scale the distance before adding it to the buffers so that we can store
+// long distances for long segments. Use this value to unscale the distance.
+#define LINE_DISTANCE_SCALE 2.0
+
+// the distance over which the line edge fades out.
+// Retina devices need a smaller distance to avoid aliasing.
+#define ANTIALIASING 1.0 / DEVICE_PIXEL_RATIO / 2.0
+
+attribute vec2 a_pos;
+attribute vec4 a_data;
+
+uniform mat4 u_matrix;
+uniform mediump float u_ratio;
+uniform vec2 u_patternscale_a;
+uniform float u_tex_y_a;
+uniform vec2 u_patternscale_b;
+uniform float u_tex_y_b;
+uniform vec2 u_gl_units_to_pixels;
+uniform mediump float u_width;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying vec2 v_tex_a;
+varying vec2 v_tex_b;
+varying float v_gamma_scale;
+
+uniform lowp float a_color_t;
+attribute lowp vec4 a_color_min;
+attribute lowp vec4 a_color_max;
+varying lowp vec4 color;
+uniform lowp float a_blur_t;
+attribute lowp float a_blur_min;
+attribute lowp float a_blur_max;
+varying lowp float blur;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_gapwidth_t;
+attribute mediump float a_gapwidth_min;
+attribute mediump float a_gapwidth_max;
+varying mediump float gapwidth;
+uniform lowp float a_offset_t;
+attribute lowp float a_offset_min;
+attribute lowp float a_offset_max;
+varying lowp float offset;
+
+void main() {
+ color = mix(a_color_min, a_color_max, a_color_t);
+ blur = mix(a_blur_min, a_blur_max, a_blur_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+ offset = mix(a_offset_min, a_offset_max, a_offset_t);
+
+ vec2 a_extrude = a_data.xy - 128.0;
+ float a_direction = mod(a_data.z, 4.0) - 1.0;
+ float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE;
+
+ // We store the texture normals in the most insignificant bit
+ // transform y so that 0 => -1 and 1 => 1
+ // In the texture normal, x is 0 if the normal points straight up/down and 1 if it's a round cap
+ // y is 1 if the normal points up, and -1 if it points down
+ mediump vec2 normal = mod(a_pos, 2.0);
+ normal.y = sign(normal.y - 0.5);
+ v_normal = normal;
+
+ // these transformations used to be applied in the JS and native code bases.
+ // moved them into the shader for clarity and simplicity.
+ gapwidth = gapwidth / 2.0;
+ float width = u_width / 2.0;
+ offset = -1.0 * offset;
+
+ float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
+ float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
+
+ // Scale the extrusion vector down to a normal and then up by the line width
+ // of this vertex.
+ mediump vec2 dist =outset * a_extrude * scale;
+
+ // Calculate the offset when drawing a line that is to the side of the actual line.
+ // We do this by creating a vector that points towards the extrude, but rotate
+ // it when we're drawing round end points (a_direction = -1 or 1) since their
+ // extrude vector points in another direction.
+ mediump float u = 0.5 * a_direction;
+ mediump float t = 1.0 - abs(u);
+ mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
+
+ // Remove the texture normal bit to get the position
+ vec2 pos = floor(a_pos * 0.5);
+
+ vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0);
+ gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude;
+
+ // calculate how much the perspective view squishes or stretches the extrude
+ float extrude_length_without_perspective = length(dist);
+ float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
+ v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+
+ v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);
+ v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);
+
+ v_width2 = vec2(outset, inset);
+}
+
+)MBGL_SHADER";
+const char* line_sdf::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+uniform sampler2D u_image;
+uniform float u_sdfgamma;
+uniform float u_mix;
+
+varying vec2 v_normal;
+varying vec2 v_width2;
+varying vec2 v_tex_a;
+varying vec2 v_tex_b;
+varying float v_gamma_scale;
+
+varying lowp vec4 color;
+varying lowp float blur;
+varying lowp float opacity;
+
+void main() {
+
+
+
+
+ // Calculate the distance of the pixel from the line in pixels.
+ float dist = length(v_normal) * v_width2.s;
+
+ // Calculate the antialiasing fade factor. This is either when fading in
+ // the line in case of an offset line (v_width2.t) or when fading out
+ // (v_width2.s)
+ float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * v_gamma_scale;
+ float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0);
+
+ float sdfdist_a = texture2D(u_image, v_tex_a).a;
+ float sdfdist_b = texture2D(u_image, v_tex_b).a;
+ float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);
+ alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/line_sdf.hpp b/src/mbgl/shaders/line_sdf.hpp
new file mode 100644
index 0000000000..1d4b566f25
--- /dev/null
+++ b/src/mbgl/shaders/line_sdf.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class line_sdf {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/raster.cpp b/src/mbgl/shaders/raster.cpp
new file mode 100644
index 0000000000..ba0aa5cd05
--- /dev/null
+++ b/src/mbgl/shaders/raster.cpp
@@ -0,0 +1,150 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/raster.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* raster::name = "raster";
+const char* raster::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+uniform mat4 u_matrix;
+uniform vec2 u_tl_parent;
+uniform float u_scale_parent;
+uniform float u_buffer_scale;
+
+attribute vec2 a_pos;
+attribute vec2 a_texture_pos;
+
+varying vec2 v_pos0;
+varying vec2 v_pos1;
+
+void main() {
+ gl_Position = u_matrix * vec4(a_pos, 0, 1);
+ v_pos0 = (((a_texture_pos / 32767.0) - 0.5) / u_buffer_scale ) + 0.5;
+ v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent;
+}
+
+)MBGL_SHADER";
+const char* raster::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform float u_fade_t;
+uniform float u_opacity;
+uniform sampler2D u_image0;
+uniform sampler2D u_image1;
+varying vec2 v_pos0;
+varying vec2 v_pos1;
+
+uniform float u_brightness_low;
+uniform float u_brightness_high;
+
+uniform float u_saturation_factor;
+uniform float u_contrast_factor;
+uniform vec3 u_spin_weights;
+
+void main() {
+
+ // read and cross-fade colors from the main and parent tiles
+ vec4 color0 = texture2D(u_image0, v_pos0);
+ vec4 color1 = texture2D(u_image1, v_pos1);
+ vec4 color = mix(color0, color1, u_fade_t);
+ color.a *= u_opacity;
+ vec3 rgb = color.rgb;
+
+ // spin
+ rgb = vec3(
+ dot(rgb, u_spin_weights.xyz),
+ dot(rgb, u_spin_weights.zxy),
+ dot(rgb, u_spin_weights.yzx));
+
+ // saturation
+ float average = (color.r + color.g + color.b) / 3.0;
+ rgb += (average - rgb) * u_saturation_factor;
+
+ // contrast
+ rgb = (rgb - 0.5) * u_contrast_factor + 0.5;
+
+ // brightness
+ vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low);
+ vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high);
+
+ gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb) * color.a, color.a);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/raster.hpp b/src/mbgl/shaders/raster.hpp
new file mode 100644
index 0000000000..791e2c8be0
--- /dev/null
+++ b/src/mbgl/shaders/raster.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class raster {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp
new file mode 100644
index 0000000000..e6728e15de
--- /dev/null
+++ b/src/mbgl/shaders/symbol_icon.cpp
@@ -0,0 +1,151 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/symbol_icon.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* symbol_icon::name = "symbol_icon";
+const char* symbol_icon::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+attribute vec2 a_pos;
+attribute vec2 a_offset;
+attribute vec2 a_texture_pos;
+attribute vec4 a_data;
+
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+
+// matrix is for the vertex position.
+uniform mat4 u_matrix;
+
+uniform mediump float u_zoom;
+uniform bool u_rotate_with_map;
+uniform vec2 u_extrude_scale;
+
+uniform vec2 u_texsize;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+
+void main() {
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+
+ vec2 a_tex = a_texture_pos.xy;
+ mediump float a_labelminzoom = a_data[0];
+ mediump vec2 a_zoom = a_data.pq;
+ mediump float a_minzoom = a_zoom[0];
+ mediump float a_maxzoom = a_zoom[1];
+
+ // u_zoom is the current zoom level adjusted for the change in font size
+ mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+
+ vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ if (u_rotate_with_map) {
+ gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
+ gl_Position.z += z * gl_Position.w;
+ } else {
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ }
+
+ v_tex = a_tex / u_texsize;
+ v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);
+}
+
+)MBGL_SHADER";
+const char* symbol_icon::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+uniform sampler2D u_texture;
+uniform sampler2D u_fadetexture;
+
+varying lowp float opacity;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+
+void main() {
+
+
+ lowp float alpha = texture2D(u_fadetexture, v_fade_tex).a * opacity;
+ gl_FragColor = texture2D(u_texture, v_tex) * alpha;
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_icon.hpp b/src/mbgl/shaders/symbol_icon.hpp
new file mode 100644
index 0000000000..eccf17602d
--- /dev/null
+++ b/src/mbgl/shaders/symbol_icon.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class symbol_icon {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp
new file mode 100644
index 0000000000..e087242bf8
--- /dev/null
+++ b/src/mbgl/shaders/symbol_sdf.cpp
@@ -0,0 +1,242 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#include <mbgl/shaders/symbol_sdf.hpp>
+
+namespace mbgl {
+namespace shaders {
+
+const char* symbol_sdf::name = "symbol_sdf";
+const char* symbol_sdf::vertexSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision highp float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+
+float evaluate_zoom_function_1(const vec4 values, const float t) {
+ if (t < 1.0) {
+ return mix(values[0], values[1], t);
+ } else if (t < 2.0) {
+ return mix(values[1], values[2], t - 1.0);
+ } else {
+ return mix(values[2], values[3], t - 2.0);
+ }
+}
+vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 value2, const vec4 value3, const float t) {
+ if (t < 1.0) {
+ return mix(value0, value1, t);
+ } else if (t < 2.0) {
+ return mix(value1, value2, t - 1.0);
+ } else {
+ return mix(value2, value3, t - 2.0);
+ }
+}
+
+// The offset depends on how many pixels are between the world origin and the edge of the tile:
+// vec2 offset = mod(pixel_coord, size)
+//
+// At high zoom levels there are a ton of pixels between the world origin and the edge of the tile.
+// The glsl spec only guarantees 16 bits of precision for highp floats. We need more than that.
+//
+// The pixel_coord is passed in as two 16 bit values:
+// pixel_coord_upper = floor(pixel_coord / 2^16)
+// pixel_coord_lower = mod(pixel_coord, 2^16)
+//
+// The offset is calculated in a series of steps that should preserve this precision:
+vec2 get_pattern_pos(const vec2 pixel_coord_upper, const vec2 pixel_coord_lower,
+ const vec2 pattern_size, const float tile_units_to_pixels, const vec2 pos) {
+
+ vec2 offset = mod(mod(mod(pixel_coord_upper, pattern_size) * 256.0, pattern_size) * 256.0 + pixel_coord_lower, pattern_size);
+ return (tile_units_to_pixels * pos + offset) / pattern_size;
+}
+const float PI = 3.141592653589793;
+
+attribute vec2 a_pos;
+attribute vec2 a_offset;
+attribute vec2 a_texture_pos;
+attribute vec4 a_data;
+
+uniform lowp float a_fill_color_t;
+attribute lowp vec4 a_fill_color_min;
+attribute lowp vec4 a_fill_color_max;
+varying lowp vec4 fill_color;
+uniform lowp float a_halo_color_t;
+attribute lowp vec4 a_halo_color_min;
+attribute lowp vec4 a_halo_color_max;
+varying lowp vec4 halo_color;
+uniform lowp float a_opacity_t;
+attribute lowp float a_opacity_min;
+attribute lowp float a_opacity_max;
+varying lowp float opacity;
+uniform lowp float a_halo_width_t;
+attribute lowp float a_halo_width_min;
+attribute lowp float a_halo_width_max;
+varying lowp float halo_width;
+uniform lowp float a_halo_blur_t;
+attribute lowp float a_halo_blur_min;
+attribute lowp float a_halo_blur_max;
+varying lowp float halo_blur;
+
+// matrix is for the vertex position.
+uniform mat4 u_matrix;
+
+uniform mediump float u_zoom;
+uniform bool u_rotate_with_map;
+uniform bool u_pitch_with_map;
+uniform mediump float u_pitch;
+uniform mediump float u_bearing;
+uniform mediump float u_aspect_ratio;
+uniform vec2 u_extrude_scale;
+
+uniform vec2 u_texsize;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+varying float v_gamma_scale;
+
+void main() {
+ fill_color = mix(a_fill_color_min, a_fill_color_max, a_fill_color_t);
+ halo_color = mix(a_halo_color_min, a_halo_color_max, a_halo_color_t);
+ opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ halo_width = mix(a_halo_width_min, a_halo_width_max, a_halo_width_t);
+ halo_blur = mix(a_halo_blur_min, a_halo_blur_max, a_halo_blur_t);
+
+ vec2 a_tex = a_texture_pos.xy;
+ mediump float a_labelminzoom = a_data[0];
+ mediump vec2 a_zoom = a_data.pq;
+ mediump float a_minzoom = a_zoom[0];
+ mediump float a_maxzoom = a_zoom[1];
+
+ // u_zoom is the current zoom level adjusted for the change in font size
+ mediump float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom));
+
+ // pitch-alignment: map
+ // rotation-alignment: map | viewport
+ if (u_pitch_with_map) {
+ lowp float angle = u_rotate_with_map ? (a_data[1] / 256.0 * 2.0 * PI) : u_bearing;
+ lowp float asin = sin(angle);
+ lowp float acos = cos(angle);
+ mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);
+ vec2 offset = RotationMatrix * a_offset;
+ vec2 extrude = u_extrude_scale * (offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
+ gl_Position.z += z * gl_Position.w;
+ // pitch-alignment: viewport
+ // rotation-alignment: map
+ } else if (u_rotate_with_map) {
+ // foreshortening factor to apply on pitched maps
+ // as a label goes from horizontal <=> vertical in angle
+ // it goes from 0% foreshortening to up to around 70% foreshortening
+ lowp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));
+
+ lowp float lineangle = a_data[1] / 256.0 * 2.0 * PI;
+
+ // use the lineangle to position points a,b along the line
+ // project the points and calculate the label angle in projected space
+ // this calculation allows labels to be rendered unskewed on pitched maps
+ vec4 a = u_matrix * vec4(a_pos, 0, 1);
+ vec4 b = u_matrix * vec4(a_pos + vec2(cos(lineangle),sin(lineangle)), 0, 1);
+ lowp float angle = atan((b[1]/b[3] - a[1]/a[3])/u_aspect_ratio, b[0]/b[3] - a[0]/a[3]);
+ lowp float asin = sin(angle);
+ lowp float acos = cos(angle);
+ mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);
+
+ vec2 offset = RotationMatrix * (vec2((1.0-pitchfactor)+(pitchfactor*cos(angle*2.0)), 1.0) * a_offset);
+ vec2 extrude = u_extrude_scale * (offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ gl_Position.z += z * gl_Position.w;
+ // pitch-alignment: viewport
+ // rotation-alignment: viewport
+ } else {
+ vec2 extrude = u_extrude_scale * (a_offset / 64.0);
+ gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
+ }
+
+ v_gamma_scale = gl_Position.w;
+
+ v_tex = a_tex / u_texsize;
+ v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0);
+}
+
+)MBGL_SHADER";
+const char* symbol_sdf::fragmentSource = R"MBGL_SHADER(
+#ifdef GL_ES
+precision mediump float;
+#else
+
+#if !defined(lowp)
+#define lowp
+#endif
+
+#if !defined(mediump)
+#define mediump
+#endif
+
+#if !defined(highp)
+#define highp
+#endif
+
+#endif
+#define SDF_PX 8.0
+#define EDGE_GAMMA 0.105/DEVICE_PIXEL_RATIO
+
+uniform bool u_is_halo;
+varying lowp vec4 fill_color;
+varying lowp vec4 halo_color;
+varying lowp float opacity;
+varying lowp float halo_width;
+varying lowp float halo_blur;
+
+uniform sampler2D u_texture;
+uniform sampler2D u_fadetexture;
+uniform lowp float u_font_scale;
+uniform highp float u_gamma_scale;
+
+varying vec2 v_tex;
+varying vec2 v_fade_tex;
+varying float v_gamma_scale;
+
+void main() {
+
+
+
+
+
+
+ lowp vec4 color = fill_color;
+ lowp float gamma = EDGE_GAMMA / u_gamma_scale;
+ lowp float buff = (256.0 - 64.0) / 256.0;
+ if (u_is_halo) {
+ color = halo_color;
+ gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / u_gamma_scale;
+ buff = (6.0 - halo_width / u_font_scale) / SDF_PX;
+ }
+
+ lowp float dist = texture2D(u_texture, v_tex).a;
+ lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;
+ highp float gamma_scaled = gamma * v_gamma_scale;
+ highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha;
+
+ gl_FragColor = color * (alpha * opacity);
+
+#ifdef OVERDRAW_INSPECTOR
+ gl_FragColor = vec4(1.0);
+#endif
+}
+
+)MBGL_SHADER";
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/shaders/symbol_sdf.hpp b/src/mbgl/shaders/symbol_sdf.hpp
new file mode 100644
index 0000000000..d5761d5fdb
--- /dev/null
+++ b/src/mbgl/shaders/symbol_sdf.hpp
@@ -0,0 +1,16 @@
+// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
+
+#pragma once
+
+namespace mbgl {
+namespace shaders {
+
+class symbol_sdf {
+public:
+ static const char* name;
+ static const char* vertexSource;
+ static const char* fragmentSource;
+};
+
+} // namespace shaders
+} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp
index ea055ce5ec..2bf8a3095a 100644
--- a/src/mbgl/sprite/sprite_atlas.cpp
+++ b/src/mbgl/sprite/sprite_atlas.cpp
@@ -27,6 +27,23 @@ struct SpriteAtlas::Loader {
std::unique_ptr<AsyncRequest> spriteRequest;
};
+SpriteAtlasElement::SpriteAtlasElement(Rect<uint16_t> rect_,
+ std::shared_ptr<const SpriteImage> image_,
+ Size size_, float pixelRatio)
+ : pos(std::move(rect_)),
+ spriteImage(std::move(image_)),
+ relativePixelRatio(spriteImage->pixelRatio / pixelRatio) {
+
+ const float padding = 1;
+
+ const float w = spriteImage->getWidth() * relativePixelRatio;
+ const float h = spriteImage->getHeight() * relativePixelRatio;
+
+ size = {{ float(spriteImage->getWidth()), spriteImage->getHeight() }};
+ tl = {{ float(pos.x + padding) / size_.width, float(pos.y + padding) / size_.height }};
+ br = {{ float(pos.x + padding + w) / size_.width, float(pos.y + padding + h) / size_.height }};
+}
+
SpriteAtlas::SpriteAtlas(Size size_, float pixelRatio_)
: size(std::move(size_)),
pixelRatio(pixelRatio_),
@@ -115,85 +132,112 @@ void SpriteAtlas::setSprite(const std::string& name, std::shared_ptr<const Sprit
void SpriteAtlas::removeSprite(const std::string& name) {
std::lock_guard<std::mutex> lock(mutex);
- _setSprite(name);
+
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ return;
+ }
+
+ Entry& entry = it->second;
+
+ if (entry.iconRect) {
+ bin.release(*entry.iconRect);
+ }
+
+ if (entry.patternRect) {
+ bin.release(*entry.patternRect);
+ }
+
+ entries.erase(it);
}
void SpriteAtlas::_setSprite(const std::string& name,
const std::shared_ptr<const SpriteImage>& sprite) {
- if (sprite) {
- auto it = sprites.find(name);
- if (it != sprites.end()) {
- // There is already a sprite with that name in our store.
- if (it->second->image.size != sprite->image.size) {
- Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str());
- return;
- }
- it->second = sprite;
- } else {
- sprites.emplace(name, sprite);
- }
+ if (!sprite->image.valid()) {
+ Log::Warning(Event::Sprite, "invalid sprite image '%s'", name.c_str());
+ return;
+ }
- // Always add/replace the value in the dirty list.
- auto dirty_it = dirtySprites.find(name);
- if (dirty_it != dirtySprites.end()) {
- dirty_it->second = sprite;
- } else {
- dirtySprites.emplace(name, sprite);
- }
- } else if (sprites.erase(name) > 0) {
- dirtySprites.emplace(name, nullptr);
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ entries.emplace(name, Entry { sprite, {}, {} });
+ return;
+ }
+
+ Entry& entry = it->second;
+
+ // There is already a sprite with that name in our store.
+ if (entry.spriteImage->image.size != sprite->image.size) {
+ Log::Warning(Event::Sprite, "Can't change sprite dimensions for '%s'", name.c_str());
+ return;
+ }
+
+ entry.spriteImage = sprite;
+
+ if (entry.iconRect) {
+ copy(entry, &Entry::iconRect);
+ }
+
+ if (entry.patternRect) {
+ copy(entry, &Entry::patternRect);
}
}
std::shared_ptr<const SpriteImage> SpriteAtlas::getSprite(const std::string& name) {
std::lock_guard<std::mutex> lock(mutex);
- const auto it = sprites.find(name);
- if (it != sprites.end()) {
- return it->second;
+ const auto it = entries.find(name);
+ if (it != entries.end()) {
+ return it->second.spriteImage;
} else {
- if (!sprites.empty()) {
+ if (!entries.empty()) {
Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str());
}
return nullptr;
}
}
-Rect<uint16_t> SpriteAtlas::allocateImage(const SpriteImage& spriteImage) {
-
- const uint16_t pixel_width = std::ceil(spriteImage.image.size.width / pixelRatio);
- const uint16_t pixel_height = std::ceil(spriteImage.image.size.height / pixelRatio);
-
- // Increase to next number divisible by 4, but at least 1.
- // This is so we can scale down the texture coordinates and pack them
- // into 2 bytes rather than 4 bytes.
- const uint16_t pack_width = (pixel_width + 1) + (4 - (pixel_width + 1) % 4);
- const uint16_t pack_height = (pixel_height + 1) + (4 - (pixel_height + 1) % 4);
-
- // We have to allocate a new area in the bin, and store an empty image in it.
- // Add a 1px border around every image.
- Rect<uint16_t> rect = bin.allocate(pack_width, pack_height);
- if (rect.w == 0) {
- return rect;
- }
+optional<SpriteAtlasElement> SpriteAtlas::getIcon(const std::string& name) {
+ return getImage(name, &Entry::iconRect);
+}
- return rect;
+optional<SpriteAtlasElement> SpriteAtlas::getPattern(const std::string& name) {
+ return getImage(name, &Entry::patternRect);
}
optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
- const SpritePatternMode mode) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
+ optional<Rect<uint16_t>> Entry::*entryRect) {
+ std::lock_guard<std::mutex> lock(mutex);
- auto rect_it = images.find({ name, mode });
- if (rect_it != images.end()) {
- return SpriteAtlasElement { rect_it->second.pos, rect_it->second.spriteImage, rect_it->second.spriteImage->pixelRatio / pixelRatio };
+ auto it = entries.find(name);
+ if (it == entries.end()) {
+ if (!entries.empty()) {
+ Log::Info(Event::Sprite, "Can't find sprite named '%s'", name.c_str());
+ }
+ return {};
}
- auto sprite = getSprite(name);
- if (!sprite) {
- return {};
+ Entry& entry = it->second;
+
+ if (entry.*entryRect) {
+ return SpriteAtlasElement {
+ *(entry.*entryRect),
+ entry.spriteImage,
+ size,
+ pixelRatio
+ };
}
- Rect<uint16_t> rect = allocateImage(*sprite);
+ const uint16_t pixelWidth = std::ceil(entry.spriteImage->image.size.width / pixelRatio);
+ const uint16_t pixelHeight = std::ceil(entry.spriteImage->image.size.height / pixelRatio);
+
+ // Increase to next number divisible by 4, but at least 1.
+ // This is so we can scale down the texture coordinates and pack them
+ // into 2 bytes rather than 4 bytes.
+ const uint16_t packWidth = (pixelWidth + 1) + (4 - (pixelWidth + 1) % 4);
+ const uint16_t packHeight = (pixelHeight + 1) + (4 - (pixelHeight + 1) % 4);
+
+ // We have to allocate a new area in the bin, and store an empty image in it.
+ Rect<uint16_t> rect = bin.allocate(packWidth, packHeight);
if (rect.w == 0) {
if (debug::spriteWarnings) {
Log::Warning(Event::Sprite, "sprite atlas bitmap overflow");
@@ -201,112 +245,44 @@ optional<SpriteAtlasElement> SpriteAtlas::getImage(const std::string& name,
return {};
}
- const Holder& holder = images.emplace(Key{ name, mode }, Holder{ sprite, rect }).first->second;
- copy(holder, mode);
-
- return SpriteAtlasElement { rect, sprite, sprite->pixelRatio / pixelRatio };
-}
-
-optional<SpriteAtlasPosition> SpriteAtlas::getPosition(const std::string& name,
- const SpritePatternMode mode) {
- std::lock_guard<std::recursive_mutex> lock(mtx);
-
- auto img = getImage(name, mode);
- if (!img) {
- return {};
- }
-
- auto rect = (*img).pos;
-
- const float padding = 1;
- auto spriteImage = (*img).spriteImage;
-
- const float w = spriteImage->getWidth() * (*img).relativePixelRatio;
- const float h = spriteImage->getHeight() * (*img).relativePixelRatio;
+ entry.*entryRect = rect;
+ copy(entry, entryRect);
- return SpriteAtlasPosition {
- {{ float(spriteImage->getWidth()), spriteImage->getHeight() }},
- {{ float(rect.x + padding) / size.width, float(rect.y + padding) / size.height }},
- {{ float(rect.x + padding + w) / size.width, float(rect.y + padding + h) / size.height }}
+ return SpriteAtlasElement {
+ rect,
+ entry.spriteImage,
+ size,
+ pixelRatio
};
}
-void copyBitmap(const uint32_t *src, const uint32_t srcStride, const uint32_t srcX, const uint32_t srcY,
- uint32_t *const dst, const uint32_t dstStride, const uint32_t dstX, const uint32_t dstY, int dstSize,
- const int width, const int height, const SpritePatternMode mode) {
-
- int srcI = srcY * srcStride + srcX;
- int dstI = dstY * dstStride + dstX;
- int x, y;
-
- if (mode == SpritePatternMode::Repeating) {
- // add 1 pixel wrapped padding on each side of the image
- dstI -= dstStride;
- for (y = -1; y <= height; y++, srcI = ((y + height) % height + srcY) * srcStride + srcX, dstI += dstStride) {
- for (x = -1; x <= width; x++) {
- const int dstIndex = (dstI + x + dstSize) % dstSize;
- dst[dstIndex] = src[srcI + ((x + width) % width)];
- }
- }
-
- } else {
- for (y = 0; y < height; y++, srcI += srcStride, dstI += dstStride) {
- for (x = 0; x < width; x++) {
- const int dstIndex = (dstI + x + dstSize) % dstSize;
- dst[dstIndex] = src[srcI + x];
- }
- }
- }
-}
-
-void SpriteAtlas::copy(const Holder& holder, const SpritePatternMode mode) {
+void SpriteAtlas::copy(const Entry& entry, optional<Rect<uint16_t>> Entry::*entryRect) {
if (!image.valid()) {
image = PremultipliedImage({ static_cast<uint32_t>(std::ceil(size.width * pixelRatio)),
static_cast<uint32_t>(std::ceil(size.height * pixelRatio)) });
- std::fill(image.data.get(), image.data.get() + image.bytes(), 0);
+ image.fill(0);
}
- const uint32_t* srcData =
- reinterpret_cast<const uint32_t*>(holder.spriteImage->image.data.get());
- if (!srcData) return;
- uint32_t* const dstData = reinterpret_cast<uint32_t*>(image.data.get());
-
- const int padding = 1;
+ const PremultipliedImage& src = entry.spriteImage->image;
+ const Rect<uint16_t>& rect = *(entry.*entryRect);
- copyBitmap(srcData, holder.spriteImage->image.size.width, 0, 0, dstData, image.size.width,
- (holder.pos.x + padding) * pixelRatio, (holder.pos.y + padding) * pixelRatio,
- image.size.width * image.size.height, holder.spriteImage->image.size.width,
- holder.spriteImage->image.size.height, mode);
+ const uint32_t padding = 1;
+ const uint32_t x = (rect.x + padding) * pixelRatio;
+ const uint32_t y = (rect.y + padding) * pixelRatio;
+ const uint32_t w = src.size.width;
+ const uint32_t h = src.size.height;
- dirty = true;
-}
-
-void SpriteAtlas::updateDirty() {
- std::lock_guard<std::recursive_mutex> lock(mtx);
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x, y }, { w, h });
- auto imageIterator = images.begin();
- auto spriteIterator = dirtySprites.begin();
- while (imageIterator != images.end() && spriteIterator != dirtySprites.end()) {
- if (imageIterator->first.first < spriteIterator->first) {
- ++imageIterator;
- } else if (spriteIterator->first < imageIterator->first.first) {
- ++spriteIterator;
- } else {
- // The two names match;
- Holder& holder = imageIterator->second;
- holder.spriteImage = spriteIterator->second;
- if (holder.spriteImage != nullptr) {
- copy(holder, imageIterator->first.second);
- ++imageIterator;
- } else {
- images.erase(imageIterator++);
- }
- // Don't advance the spriteIterator because there might be another sprite with the same
- // name, but a different wrap value.
- }
+ if (entryRect == &Entry::patternRect) {
+ // Add 1 pixel wrapped padding on each side of the image.
+ PremultipliedImage::copy(src, image, { 0, h - 1 }, { x, y - 1 }, { w, 1 }); // T
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x, y + h }, { w, 1 }); // B
+ PremultipliedImage::copy(src, image, { w - 1, 0 }, { x - 1, y }, { 1, h }); // L
+ PremultipliedImage::copy(src, image, { 0, 0 }, { x + w, y }, { 1, h }); // R
}
- dirtySprites.clear();
+ dirty = true;
}
void SpriteAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
@@ -333,11 +309,4 @@ void SpriteAtlas::bind(bool linear, gl::Context& context, gl::TextureUnit unit)
linear ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
}
-SpriteAtlas::Holder::Holder(std::shared_ptr<const SpriteImage> spriteImage_, Rect<uint16_t> pos_)
- : spriteImage(std::move(spriteImage_)), pos(std::move(pos_)) {
-}
-
-SpriteAtlas::Holder::Holder(Holder&& h) : spriteImage(std::move(h.spriteImage)), pos(h.pos) {
-}
-
} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp
index c79aec135e..c7b266376b 100644
--- a/src/mbgl/sprite/sprite_atlas.hpp
+++ b/src/mbgl/sprite/sprite_atlas.hpp
@@ -10,7 +10,7 @@
#include <string>
#include <map>
#include <mutex>
-#include <unordered_set>
+#include <unordered_map>
#include <array>
#include <memory>
@@ -23,26 +23,17 @@ namespace gl {
class Context;
} // namespace gl
-class SpriteImage;
-class SpritePosition;
-
-class SpriteAtlasPosition {
-public:
- std::array<float, 2> size = {{ 0, 0 }};
- std::array<float, 2> tl = {{ 0, 0 }};
- std::array<float, 2> br = {{ 0, 0 }};
-};
-
class SpriteAtlasElement {
public:
+ SpriteAtlasElement(Rect<uint16_t>, std::shared_ptr<const SpriteImage>, Size size, float pixelRatio);
+
Rect<uint16_t> pos;
std::shared_ptr<const SpriteImage> spriteImage;
- float relativePixelRatio;
-};
-enum class SpritePatternMode : bool {
- Single = false,
- Repeating = true,
+ float relativePixelRatio;
+ std::array<float, 2> size;
+ std::array<float, 2> tl;
+ std::array<float, 2> br;
};
class SpriteAtlas : public util::noncopyable {
@@ -62,32 +53,17 @@ public:
void setObserver(SpriteAtlasObserver*);
- // Adds/replaces a Sprite image.
void setSprite(const std::string&, std::shared_ptr<const SpriteImage>);
-
- // Adds/replaces mutliple Sprite images.
- void setSprites(const Sprites& sprites);
-
- // Removes a Sprite.
void removeSprite(const std::string&);
- // Obtains a Sprite image.
std::shared_ptr<const SpriteImage> getSprite(const std::string&);
- // If the sprite is loaded, copies the requsted image from it into the atlas and returns
- // the resulting icon measurements. If not, returns an empty optional.
- optional<SpriteAtlasElement> getImage(const std::string& name, SpritePatternMode mode);
-
- // This function is used for getting the position during render time.
- optional<SpriteAtlasPosition> getPosition(const std::string& name,
- SpritePatternMode mode = SpritePatternMode::Single);
+ optional<SpriteAtlasElement> getIcon(const std::string& name);
+ optional<SpriteAtlasElement> getPattern(const std::string& name);
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
void bind(bool linear, gl::Context&, gl::TextureUnit unit);
- // Updates sprites in the atlas texture that may have changed.
- void updateDirty();
-
// Uploads the texture to the GPU to be available when we need it. This is a lazy operation;
// the texture is only bound when the data is out of date (=dirty).
void upload(gl::Context&, gl::TextureUnit unit);
@@ -96,6 +72,7 @@ public:
float getPixelRatio() const { return pixelRatio; }
// Only for use in tests.
+ void setSprites(const Sprites& sprites);
const PremultipliedImage& getAtlasImage() const {
return image;
}
@@ -104,6 +81,7 @@ private:
void _setSprite(const std::string&, const std::shared_ptr<const SpriteImage>& = nullptr);
void emitSpriteLoadedIfComplete();
+
const Size size;
const float pixelRatio;
@@ -114,35 +92,26 @@ private:
SpriteAtlasObserver* observer = nullptr;
- // Lock for sprites and dirty maps.
- std::mutex mutex;
-
- // Stores all current sprites.
- Sprites sprites;
-
- // Stores all Sprite IDs that changed since the last invocation.
- Sprites dirtySprites;
-
- struct Holder : private util::noncopyable {
- Holder(std::shared_ptr<const SpriteImage>, Rect<uint16_t>);
- Holder(Holder&&);
+ struct Entry {
std::shared_ptr<const SpriteImage> spriteImage;
- const Rect<uint16_t> pos;
- };
- using Key = std::pair<std::string, SpritePatternMode>;
+ // One sprite image might be used as both an icon image and a pattern image. If so,
+ // it must have two distinct entries in the texture. The one for the icon image has
+ // a single pixel transparent border, and the one for the pattern image has a single
+ // pixel border wrapped from the opposite side.
+ optional<Rect<uint16_t>> iconRect;
+ optional<Rect<uint16_t>> patternRect;
+ };
- Rect<uint16_t> allocateImage(const SpriteImage&);
- void copy(const Holder& holder, SpritePatternMode mode);
+ optional<SpriteAtlasElement> getImage(const std::string& name, optional<Rect<uint16_t>> Entry::*rect);
+ void copy(const Entry&, optional<Rect<uint16_t>> Entry::*rect);
- std::recursive_mutex mtx;
+ std::mutex mutex;
+ std::unordered_map<std::string, Entry> entries;
BinPack<uint16_t> bin;
- std::map<Key, Holder> images;
- std::unordered_set<std::string> uninitialized;
PremultipliedImage image;
mbgl::optional<gl::Texture> texture;
std::atomic<bool> dirty;
- static const int buffer = 1;
};
} // namespace mbgl
diff --git a/src/mbgl/sprite/sprite_parser.cpp b/src/mbgl/sprite/sprite_parser.cpp
index 9de8515e14..66b5ec0606 100644
--- a/src/mbgl/sprite/sprite_parser.cpp
+++ b/src/mbgl/sprite/sprite_parser.cpp
@@ -34,17 +34,8 @@ SpriteImagePtr createSpriteImage(const PremultipliedImage& image,
PremultipliedImage dstImage({ width, height });
- auto srcData = reinterpret_cast<const uint32_t*>(image.data.get());
- auto dstData = reinterpret_cast<uint32_t*>(dstImage.data.get());
-
// Copy from the source image into our individual sprite image
- for (uint32_t y = 0; y < height; ++y) {
- const auto dstRow = y * width;
- const auto srcRow = (y + srcY) * image.size.width + srcX;
- for (uint32_t x = 0; x < width; ++x) {
- dstData[dstRow + x] = srcData[srcRow + x];
- }
- }
+ PremultipliedImage::copy(image, dstImage, { srcX, srcY }, { 0, 0 }, { width, height });
return std::make_unique<const SpriteImage>(std::move(dstImage), ratio, sdf);
}
diff --git a/src/mbgl/storage/local_file_source.hpp b/src/mbgl/storage/local_file_source.hpp
index 5d665c3848..43319bc06e 100644
--- a/src/mbgl/storage/local_file_source.hpp
+++ b/src/mbgl/storage/local_file_source.hpp
@@ -14,7 +14,7 @@ public:
~LocalFileSource() override;
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
-
+
static bool acceptsURL(const std::string& url);
private:
diff --git a/src/mbgl/style/bucket_parameters.cpp b/src/mbgl/style/bucket_parameters.cpp
index e641120c5e..2b02ac4a4a 100644
--- a/src/mbgl/style/bucket_parameters.cpp
+++ b/src/mbgl/style/bucket_parameters.cpp
@@ -1,21 +1,7 @@
#include <mbgl/style/bucket_parameters.hpp>
-#include <mbgl/style/filter_evaluator.hpp>
-#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {
-void BucketParameters::eachFilteredFeature(const Filter& filter,
- const GeometryTileLayer& layer,
- std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)> function) {
- auto name = layer.getName();
- for (std::size_t i = 0; !cancelled() && i < layer.featureCount(); i++) {
- auto feature = layer.getFeature(i);
- if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
- continue;
- function(*feature, i, name);
- }
-}
-
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/bucket_parameters.hpp b/src/mbgl/style/bucket_parameters.hpp
index d5e05c5dd2..d0edbcac30 100644
--- a/src/mbgl/style/bucket_parameters.hpp
+++ b/src/mbgl/style/bucket_parameters.hpp
@@ -2,33 +2,14 @@
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/style/filter.hpp>
-
-#include <atomic>
-#include <functional>
namespace mbgl {
-
-class GeometryTileLayer;
-class GeometryTileFeature;
-class FeatureIndex;
-
namespace style {
class BucketParameters {
public:
- const OverscaledTileID& tileID;
- const std::atomic<bool>& obsolete;
- FeatureIndex& featureIndex;
+ const OverscaledTileID tileID;
const MapMode mode;
-
- bool cancelled() const {
- return obsolete;
- }
-
- void eachFilteredFeature(const Filter&,
- const GeometryTileLayer&,
- std::function<void (const GeometryTileFeature&, std::size_t index, const std::string& layerName)>);
};
} // namespace style
diff --git a/src/mbgl/style/conversion/stringify.hpp b/src/mbgl/style/conversion/stringify.hpp
index d06b2f2814..4afbf198e5 100644
--- a/src/mbgl/style/conversion/stringify.hpp
+++ b/src/mbgl/style/conversion/stringify.hpp
@@ -103,6 +103,29 @@ void stringify(Writer& writer, const Value& v) {
}
template <class Writer>
+void stringify(Writer& writer, FeatureType type) {
+ switch (type) {
+ case FeatureType::Unknown:
+ writer.String("Unknown");
+ break;
+ case FeatureType::Point:
+ writer.String("Point");
+ break;
+ case FeatureType::LineString:
+ writer.String("LineString");
+ break;
+ case FeatureType::Polygon:
+ writer.String("Polygon");
+ break;
+ }
+}
+
+template <class Writer>
+void stringify(Writer& writer, const FeatureIdentifier& id) {
+ FeatureIdentifier::visit(id, [&] (const auto& id_) { stringify(writer, id_); });
+}
+
+template <class Writer>
class StringifyFilter {
public:
Writer& writer;
@@ -156,28 +179,78 @@ public:
}
void operator()(const HasFilter& f) {
- stringifyUnaryFilter(f, "has");
+ stringifyUnaryFilter("has", f.key);
}
void operator()(const NotHasFilter& f) {
- stringifyUnaryFilter(f, "!has");
+ stringifyUnaryFilter("!has", f.key);
+ }
+
+ void operator()(const TypeEqualsFilter& f) {
+ stringifyBinaryFilter(f, "==", "$type");
+ }
+
+ void operator()(const TypeNotEqualsFilter& f) {
+ stringifyBinaryFilter(f, "!=", "$type");
+ }
+
+ void operator()(const TypeInFilter& f) {
+ stringifySetFilter(f, "in", "$type");
+ }
+
+ void operator()(const TypeNotInFilter& f) {
+ stringifySetFilter(f, "!in", "$type");
+ }
+
+ void operator()(const IdentifierEqualsFilter& f) {
+ stringifyBinaryFilter(f, "==", "$id");
+ }
+
+ void operator()(const IdentifierNotEqualsFilter& f) {
+ stringifyBinaryFilter(f, "!=", "$id");
+ }
+
+ void operator()(const IdentifierInFilter& f) {
+ stringifySetFilter(f, "in", "$id");
+ }
+
+ void operator()(const IdentifierNotInFilter& f) {
+ stringifySetFilter(f, "!in", "$id");
+ }
+
+ void operator()(const HasIdentifierFilter&) {
+ stringifyUnaryFilter("has", "$id");
+ }
+
+ void operator()(const NotHasIdentifierFilter&) {
+ stringifyUnaryFilter("!has", "$id");
}
private:
template <class F>
void stringifyBinaryFilter(const F& f, const char * op) {
+ stringifyBinaryFilter(f, op, f.key);
+ }
+
+ template <class F>
+ void stringifyBinaryFilter(const F& f, const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
stringify(writer, f.value);
writer.EndArray();
}
template <class F>
void stringifySetFilter(const F& f, const char * op) {
+ stringifySetFilter(f, op, f.key);
+ }
+
+ template <class F>
+ void stringifySetFilter(const F& f, const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
for (const auto& value : f.values) {
stringify(writer, value);
}
@@ -194,11 +267,10 @@ private:
writer.EndArray();
}
- template <class F>
- void stringifyUnaryFilter(const F& f, const char * op) {
+ void stringifyUnaryFilter(const char * op, const std::string& key) {
writer.StartArray();
writer.String(op);
- writer.String(f.key);
+ writer.String(key);
writer.EndArray();
}
};
@@ -214,20 +286,137 @@ void stringify(Writer& writer, const Undefined&) {
writer.Null();
}
-template <class Writer, class T>
-void stringify(Writer& writer, const Function<T>& f) {
- writer.StartObject();
- writer.Key("base");
- writer.Double(f.getBase());
- writer.Key("stops");
- writer.StartArray();
- for (const auto& stop : f.getStops()) {
+template <class Writer>
+void stringify(Writer& writer, const CategoricalValue& v) {
+ CategoricalValue::visit(v, [&] (const auto& v_) { stringify(writer, v_); });
+}
+
+template <class Writer>
+class StringifyStops {
+public:
+ Writer& writer;
+
+ template <class T>
+ void operator()(const ExponentialStops<T>& f) {
+ writer.Key("type");
+ writer.String("exponential");
+ writer.Key("base");
+ writer.Double(f.base);
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const IntervalStops<T>& f) {
+ writer.Key("type");
+ writer.String("interval");
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CategoricalStops<T>& f) {
+ writer.Key("type");
+ writer.String("categorical");
+ writer.Key("stops");
+ stringifyStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const IdentityStops<T>&) {
+ writer.Key("type");
+ writer.String("identity");
+ }
+
+ template <class T>
+ void operator()(const CompositeExponentialStops<T>& f) {
+ writer.Key("type");
+ writer.String("exponential");
+ writer.Key("base");
+ writer.Double(f.base);
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CompositeIntervalStops<T>& f) {
+ writer.Key("type");
+ writer.String("interval");
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+ template <class T>
+ void operator()(const CompositeCategoricalStops<T>& f) {
+ writer.Key("type");
+ writer.String("categorical");
+ writer.Key("stops");
+ stringifyCompositeStops(f.stops);
+ }
+
+private:
+ template <class K, class V>
+ void stringifyStops(const std::map<K, V>& stops) {
writer.StartArray();
- writer.Double(stop.first);
- stringify(writer, stop.second);
+ for (const auto& stop : stops) {
+ writer.StartArray();
+ stringify(writer, stop.first);
+ stringify(writer, stop.second);
+ writer.EndArray();
+ }
writer.EndArray();
}
- writer.EndArray();
+
+ template <class InnerStops>
+ void stringifyCompositeStops(const std::map<float, InnerStops>& stops) {
+ writer.StartArray();
+ for (const auto& outer : stops) {
+ for (const auto& inner : outer.second) {
+ writer.StartArray();
+ writer.StartObject();
+ writer.Key("zoom");
+ writer.Double(outer.first);
+ writer.Key("value");
+ stringify(writer, inner.first);
+ writer.EndObject();
+ stringify(writer, inner.second);
+ writer.EndArray();
+ }
+ }
+ writer.EndArray();
+ }
+};
+
+template <class Writer, class T>
+void stringify(Writer& writer, const CameraFunction<T>& f) {
+ writer.StartObject();
+ CameraFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ writer.EndObject();
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const SourceFunction<T>& f) {
+ writer.StartObject();
+ writer.Key("property");
+ writer.String(f.property);
+ SourceFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
+ writer.EndObject();
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const CompositeFunction<T>& f) {
+ writer.StartObject();
+ writer.Key("property");
+ writer.String(f.property);
+ CompositeFunction<T>::Stops::visit(f.stops, StringifyStops<Writer> { writer });
+ if (f.defaultValue) {
+ writer.Key("default");
+ stringify(writer, *f.defaultValue);
+ }
writer.EndObject();
}
@@ -238,7 +427,20 @@ void stringify(Writer& writer, const PropertyValue<T>& v) {
template <class Property, class Writer, class T>
void stringify(Writer& writer, const PropertyValue<T>& value) {
- if (value) {
+ if (!value.isUndefined()) {
+ writer.Key(Property::key);
+ stringify(writer, value);
+ }
+}
+
+template <class Writer, class T>
+void stringify(Writer& writer, const DataDrivenPropertyValue<T>& v) {
+ v.evaluate([&] (const auto& v_) { stringify(writer, v_); });
+}
+
+template <class Property, class Writer, class T>
+void stringify(Writer& writer, const DataDrivenPropertyValue<T>& value) {
+ if (!value.isUndefined()) {
writer.Key(Property::key);
stringify(writer, value);
}
diff --git a/src/mbgl/style/cross_faded_property_evaluator.cpp b/src/mbgl/style/cross_faded_property_evaluator.cpp
index 4de939576e..796ca00bbf 100644
--- a/src/mbgl/style/cross_faded_property_evaluator.cpp
+++ b/src/mbgl/style/cross_faded_property_evaluator.cpp
@@ -17,21 +17,10 @@ Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const T& constant) const {
}
template <typename T>
-T getBiggestStopLessThan(const Function<T>& function, float z) {
- const auto& stops = function.getStops();
- for (uint32_t i = 0; i < stops.size(); i++) {
- if (stops[i].first > z) {
- return stops[i == 0 ? i : i - 1].second;
- }
- }
- return stops.at(stops.size() - 1).second;
-}
-
-template <typename T>
-Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const Function<T>& function) const {
- return calculate(getBiggestStopLessThan(function, parameters.z - 1.0f),
- getBiggestStopLessThan(function, parameters.z),
- getBiggestStopLessThan(function, parameters.z + 1.0f));
+Faded<T> CrossFadedPropertyEvaluator<T>::operator()(const CameraFunction<T>& function) const {
+ return calculate(function.evaluate(parameters.z - 1.0f),
+ function.evaluate(parameters.z),
+ function.evaluate(parameters.z + 1.0f));
}
template <typename T>
diff --git a/src/mbgl/style/cross_faded_property_evaluator.hpp b/src/mbgl/style/cross_faded_property_evaluator.hpp
index 70c8c0c978..c5642f5cfb 100644
--- a/src/mbgl/style/cross_faded_property_evaluator.hpp
+++ b/src/mbgl/style/cross_faded_property_evaluator.hpp
@@ -28,7 +28,7 @@ public:
Faded<T> operator()(const Undefined&) const;
Faded<T> operator()(const T& constant) const;
- Faded<T> operator()(const Function<T>&) const;
+ Faded<T> operator()(const CameraFunction<T>&) const;
private:
Faded<T> calculate(const T& min, const T& mid, const T& max) const;
diff --git a/src/mbgl/style/data_driven_property_evaluator.hpp b/src/mbgl/style/data_driven_property_evaluator.hpp
new file mode 100644
index 0000000000..7a0ff9a094
--- /dev/null
+++ b/src/mbgl/style/data_driven_property_evaluator.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
+#include <mbgl/style/possibly_evaluated_property_value.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <typename T>
+class DataDrivenPropertyEvaluator {
+public:
+ using ResultType = PossiblyEvaluatedPropertyValue<T>;
+
+ DataDrivenPropertyEvaluator(const PropertyEvaluationParameters& parameters_, T defaultValue_)
+ : parameters(parameters_),
+ defaultValue(std::move(defaultValue_)) {}
+
+ ResultType operator()(const Undefined&) const {
+ return ResultType(defaultValue);
+ }
+
+ ResultType operator()(const T& constant) const {
+ return ResultType(constant);
+ }
+
+ ResultType operator()(const CameraFunction<T>& function) const {
+ return ResultType(function.evaluate(parameters.z));
+ }
+
+ template <class Function>
+ ResultType operator()(const Function& function) const {
+ return ResultType(function);
+ }
+
+private:
+ const PropertyEvaluationParameters& parameters;
+ T defaultValue;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function.cpp b/src/mbgl/style/function.cpp
deleted file mode 100644
index 02750c7d2e..0000000000
--- a/src/mbgl/style/function.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <mbgl/style/function.hpp>
-#include <mbgl/style/types.hpp>
-#include <mbgl/util/color.hpp>
-#include <mbgl/util/interpolate.hpp>
-
-#include <cmath>
-
-namespace mbgl {
-namespace style {
-
-template <typename T>
-T Function<T>::evaluate(float z) const {
- bool smaller = false;
- float smaller_z = 0.0f;
- T smaller_val = T();
- bool larger = false;
- float larger_z = 0.0f;
- T larger_val = T();
-
- for (uint32_t i = 0; i < stops.size(); i++) {
- float stop_z = stops[i].first;
- T stop_val = stops[i].second;
- if (stop_z <= z && (!smaller || smaller_z < stop_z)) {
- smaller = true;
- smaller_z = stop_z;
- smaller_val = stop_val;
- }
- if (stop_z >= z && (!larger || larger_z > stop_z)) {
- larger = true;
- larger_z = stop_z;
- larger_val = stop_val;
- }
- }
-
- if (smaller && larger) {
- if (larger_z == smaller_z || larger_val == smaller_val) {
- return smaller_val;
- }
- const float zoomDiff = larger_z - smaller_z;
- const float zoomProgress = z - smaller_z;
- if (base == 1.0f) {
- const float t = zoomProgress / zoomDiff;
- return util::interpolate(smaller_val, larger_val, t);
- } else {
- const float t = (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1);
- return util::interpolate(smaller_val, larger_val, t);
- }
- } else if (larger) {
- return larger_val;
- } else if (smaller) {
- return smaller_val;
- } else {
- // No stop defined.
- assert(false);
- return T();
- }
-}
-
-template class Function<bool>;
-template class Function<float>;
-template class Function<Color>;
-template class Function<std::vector<float>>;
-template class Function<std::vector<std::string>>;
-template class Function<std::array<float, 2>>;
-template class Function<std::array<float, 4>>;
-
-template class Function<std::string>;
-template class Function<TranslateAnchorType>;
-template class Function<RotateAnchorType>;
-template class Function<CirclePitchScaleType>;
-template class Function<LineCapType>;
-template class Function<LineJoinType>;
-template class Function<SymbolPlacementType>;
-template class Function<TextAnchorType>;
-template class Function<TextJustifyType>;
-template class Function<TextTransformType>;
-template class Function<AlignmentType>;
-template class Function<IconTextFitType>;
-
-} // namespace style
-} // namespace mbgl
diff --git a/src/mbgl/style/function/categorical_stops.cpp b/src/mbgl/style/function/categorical_stops.cpp
new file mode 100644
index 0000000000..2984c3832f
--- /dev/null
+++ b/src/mbgl/style/function/categorical_stops.cpp
@@ -0,0 +1,38 @@
+#include <mbgl/style/function/categorical_stops.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace style {
+
+optional<CategoricalValue> categoricalValue(const Value& value) {
+ return value.match(
+ [] (bool t) { return optional<CategoricalValue>(t); },
+ [] (uint64_t t) { return optional<CategoricalValue>(int64_t(t)); },
+ [] (int64_t t) { return optional<CategoricalValue>(t); },
+ [] (double t) { return optional<CategoricalValue>(int64_t(t)); },
+ [] (const std::string& t) { return optional<CategoricalValue>(t); },
+ [] (const auto&) { return optional<CategoricalValue>(); }
+ );
+}
+
+template <class T>
+optional<T> CategoricalStops<T>::evaluate(const Value& value) const {
+ auto v = categoricalValue(value);
+ if (!v) {
+ return {};
+ }
+ auto it = stops.find(*v);
+ return it == stops.end() ? optional<T>() : it->second;
+}
+
+template class CategoricalStops<float>;
+template class CategoricalStops<Color>;
+template class CategoricalStops<std::array<float, 2>>;
+template class CategoricalStops<std::string>;
+template class CategoricalStops<TextTransformType>;
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/function/identity_stops.cpp b/src/mbgl/style/function/identity_stops.cpp
new file mode 100644
index 0000000000..dfb34e9dd4
--- /dev/null
+++ b/src/mbgl/style/function/identity_stops.cpp
@@ -0,0 +1,61 @@
+#include <mbgl/style/function/identity_stops.hpp>
+#include <mbgl/style/types.hpp>
+#include <mbgl/util/enum.hpp>
+#include <mbgl/util/color.hpp>
+
+#include <array>
+
+namespace mbgl {
+namespace style {
+
+template <>
+optional<float> IdentityStops<float>::evaluate(const Value& value) const {
+ return numericValue<float>(value);
+}
+
+template <>
+optional<std::string> IdentityStops<std::string>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return value.get<std::string>();
+}
+
+template <>
+optional<Color> IdentityStops<Color>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return Color::parse(value.get<std::string>());
+}
+
+template <>
+optional<TextTransformType> IdentityStops<TextTransformType>::evaluate(const Value& value) const {
+ if (!value.is<std::string>()) {
+ return {};
+ }
+
+ return Enum<TextTransformType>::toEnum(value.get<std::string>());
+}
+
+template <>
+optional<std::array<float, 2>> IdentityStops<std::array<float, 2>>::evaluate(const Value& value) const {
+ if (!value.is<std::vector<Value>>()) {
+ return {};
+ }
+
+ const std::vector<Value>& vector = value.get<std::vector<Value>>();
+ if (vector.size() != 2 || !numericValue<float>(vector[0]) || !numericValue<float>(vector[1])) {
+ return {};
+ }
+
+ return {{{
+ *numericValue<float>(vector[0]),
+ *numericValue<float>(vector[1])
+ }}};
+}
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/layer_impl.hpp b/src/mbgl/style/layer_impl.hpp
index 0fea70c10b..9b2bfe4d2c 100644
--- a/src/mbgl/style/layer_impl.hpp
+++ b/src/mbgl/style/layer_impl.hpp
@@ -61,7 +61,7 @@ public:
// Returns true if any paint properties have active transitions.
virtual bool evaluate(const PropertyEvaluationParameters&) = 0;
- virtual std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const = 0;
+ virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const = 0;
// Checks whether this layer needs to be rendered in the given render pass.
bool hasRenderPass(RenderPass) const;
diff --git a/src/mbgl/style/layer_observer.hpp b/src/mbgl/style/layer_observer.hpp
index a3f9ca7528..2fa1c39660 100644
--- a/src/mbgl/style/layer_observer.hpp
+++ b/src/mbgl/style/layer_observer.hpp
@@ -12,6 +12,7 @@ public:
virtual void onLayerFilterChanged(Layer&) {}
virtual void onLayerVisibilityChanged(Layer&) {}
virtual void onLayerPaintPropertyChanged(Layer&) {}
+ virtual void onLayerDataDrivenPaintPropertyChanged(Layer&) {}
virtual void onLayerLayoutPropertyChanged(Layer&, const char *) {}
};
diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp
index a75038bfa0..5a903f1b6b 100644
--- a/src/mbgl/style/layers/background_layer.cpp
+++ b/src/mbgl/style/layers/background_layer.cpp
@@ -55,6 +55,10 @@ void BackgroundLayer::setBackgroundColor(PropertyValue<Color> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundColor>(value, klass);
+}
+
PropertyValue<std::string> BackgroundLayer::getDefaultBackgroundPattern() {
return { "" };
}
@@ -70,6 +74,10 @@ void BackgroundLayer::setBackgroundPattern(PropertyValue<std::string> value, con
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundPattern>(value, klass);
+}
+
PropertyValue<float> BackgroundLayer::getDefaultBackgroundOpacity() {
return { 1 };
}
@@ -85,5 +93,9 @@ void BackgroundLayer::setBackgroundOpacity(PropertyValue<float> value, const opt
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void BackgroundLayer::setBackgroundOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<BackgroundOpacity>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/background_layer_impl.cpp b/src/mbgl/style/layers/background_layer_impl.cpp
index 4a8fe39c9a..f25ba9cfb4 100644
--- a/src/mbgl/style/layers/background_layer_impl.cpp
+++ b/src/mbgl/style/layers/background_layer_impl.cpp
@@ -16,7 +16,8 @@ bool BackgroundLayer::Impl::evaluate(const PropertyEvaluationParameters& paramet
return paint.hasTransition();
}
-std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> BackgroundLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/background_layer_impl.hpp b/src/mbgl/style/layers/background_layer_impl.hpp
index 4629217e6d..02a8c423d6 100644
--- a/src/mbgl/style/layers/background_layer_impl.hpp
+++ b/src/mbgl/style/layers/background_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
BackgroundPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/background_layer_properties.hpp b/src/mbgl/style/layers/background_layer_properties.hpp
index 792bf3de94..fae6c26a4b 100644
--- a/src/mbgl/style/layers/background_layer_properties.hpp
+++ b/src/mbgl/style/layers/background_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp
index 389ab93403..53248e9397 100644
--- a/src/mbgl/style/layers/circle_layer.cpp
+++ b/src/mbgl/style/layers/circle_layer.cpp
@@ -65,64 +65,96 @@ const Filter& CircleLayer::getFilter() const {
// Paint properties
-PropertyValue<float> CircleLayer::getDefaultCircleRadius() {
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleRadius() {
return { 5 };
}
-PropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleRadius(const optional<std::string>& klass) const {
return impl->paint.get<CircleRadius>(klass);
}
-void CircleLayer::setCircleRadius(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleRadius(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleRadius(klass))
return;
impl->paint.set<CircleRadius>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleRadiusTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleRadius>(value, klass);
}
-PropertyValue<Color> CircleLayer::getDefaultCircleColor() {
+DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleColor() {
return { Color::black() };
}
-PropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> CircleLayer::getCircleColor(const optional<std::string>& klass) const {
return impl->paint.get<CircleColor>(klass);
}
-void CircleLayer::setCircleColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getCircleColor(klass))
return;
impl->paint.set<CircleColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> CircleLayer::getDefaultCircleBlur() {
+void CircleLayer::setCircleColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleBlur() {
return { 0 };
}
-PropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleBlur(const optional<std::string>& klass) const {
return impl->paint.get<CircleBlur>(klass);
}
-void CircleLayer::setCircleBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleBlur(klass))
return;
impl->paint.set<CircleBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
+void CircleLayer::setCircleBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleBlur>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleOpacity() {
return { 1 };
}
-PropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleOpacity(const optional<std::string>& klass) const {
return impl->paint.get<CircleOpacity>(klass);
}
-void CircleLayer::setCircleOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleOpacity(klass))
return;
impl->paint.set<CircleOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleOpacity>(value, klass);
}
PropertyValue<std::array<float, 2>> CircleLayer::getDefaultCircleTranslate() {
@@ -140,6 +172,10 @@ void CircleLayer::setCircleTranslate(PropertyValue<std::array<float, 2>> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void CircleLayer::setCircleTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> CircleLayer::getDefaultCircleTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -155,6 +191,10 @@ void CircleLayer::setCircleTranslateAnchor(PropertyValue<TranslateAnchorType> va
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void CircleLayer::setCircleTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleTranslateAnchor>(value, klass);
+}
+
PropertyValue<CirclePitchScaleType> CircleLayer::getDefaultCirclePitchScale() {
return { CirclePitchScaleType::Map };
}
@@ -170,49 +210,77 @@ void CircleLayer::setCirclePitchScale(PropertyValue<CirclePitchScaleType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
+void CircleLayer::setCirclePitchScaleTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CirclePitchScale>(value, klass);
+}
+
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeWidth() {
return { 0 };
}
-PropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeWidth(const optional<std::string>& klass) const {
return impl->paint.get<CircleStrokeWidth>(klass);
}
-void CircleLayer::setCircleStrokeWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleStrokeWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleStrokeWidth(klass))
return;
impl->paint.set<CircleStrokeWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeWidth>(value, klass);
}
-PropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
+DataDrivenPropertyValue<Color> CircleLayer::getDefaultCircleStrokeColor() {
return { Color::black() };
}
-PropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> CircleLayer::getCircleStrokeColor(const optional<std::string>& klass) const {
return impl->paint.get<CircleStrokeColor>(klass);
}
-void CircleLayer::setCircleStrokeColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleStrokeColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getCircleStrokeColor(klass))
return;
impl->paint.set<CircleStrokeColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeColor>(value, klass);
}
-PropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
+DataDrivenPropertyValue<float> CircleLayer::getDefaultCircleStrokeOpacity() {
return { 1 };
}
-PropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> CircleLayer::getCircleStrokeOpacity(const optional<std::string>& klass) const {
return impl->paint.get<CircleStrokeOpacity>(klass);
}
-void CircleLayer::setCircleStrokeOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void CircleLayer::setCircleStrokeOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getCircleStrokeOpacity(klass))
return;
impl->paint.set<CircleStrokeOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void CircleLayer::setCircleStrokeOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<CircleStrokeOpacity>(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp
index 136522e41c..ea1d4eeb65 100644
--- a/src/mbgl/style/layers/circle_layer_impl.cpp
+++ b/src/mbgl/style/layers/circle_layer_impl.cpp
@@ -1,5 +1,4 @@
#include <mbgl/style/layers/circle_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -15,27 +14,25 @@ void CircleLayer::Impl::cascade(const CascadeParameters& parameters) {
bool CircleLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
- passes = (paint.evaluated.get<CircleRadius>() > 0 && paint.evaluated.get<CircleColor>().a > 0 && paint.evaluated.get<CircleOpacity>() > 0)
+ passes = ((paint.evaluated.get<CircleRadius>().constantOr(1) > 0 ||
+ paint.evaluated.get<CircleStrokeWidth>().constantOr(1) > 0)
+ && (paint.evaluated.get<CircleColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<CircleStrokeColor>().constantOr(Color::black()).a > 0)
+ && (paint.evaluated.get<CircleOpacity>().constantOr(1) > 0 ||
+ paint.evaluated.get<CircleStrokeOpacity>().constantOr(1) > 0))
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<CircleBucket>(parameters.mode);
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> CircleLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<CircleBucket>(parameters, layers);
}
float CircleLayer::Impl::getQueryRadius() const {
const std::array<float, 2>& translate = paint.evaluated.get<CircleTranslate>();
- return paint.evaluated.get<CircleRadius>() + util::length(translate[0], translate[1]);
+ return paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue())
+ + util::length(translate[0], translate[1]);
}
bool CircleLayer::Impl::queryIntersectsGeometry(
@@ -47,7 +44,7 @@ bool CircleLayer::Impl::queryIntersectsGeometry(
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry, paint.evaluated.get<CircleTranslate>(), paint.evaluated.get<CircleTranslateAnchor>(), bearing, pixelsToTileUnits);
- auto circleRadius = paint.evaluated.get<CircleRadius>() * pixelsToTileUnits;
+ auto circleRadius = paint.evaluated.get<CircleRadius>().constantOr(CircleRadius::defaultValue()) * pixelsToTileUnits;
return util::polygonIntersectsBufferedMultiPoint(
translatedQueryGeometry.value_or(queryGeometry), geometry, circleRadius);
diff --git a/src/mbgl/style/layers/circle_layer_impl.hpp b/src/mbgl/style/layers/circle_layer_impl.hpp
index 744a56898c..0f9611d589 100644
--- a/src/mbgl/style/layers/circle_layer_impl.hpp
+++ b/src/mbgl/style/layers/circle_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp
index ea36b31949..1cb4f5a635 100644
--- a/src/mbgl/style/layers/circle_layer_properties.hpp
+++ b/src/mbgl/style/layers/circle_layer_properties.hpp
@@ -5,23 +5,24 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
-struct CircleRadius : PaintProperty<float> {
+struct CircleRadius : DataDrivenPaintProperty<float, attributes::a_radius> {
static float defaultValue() { return 5; }
};
-struct CircleColor : PaintProperty<Color> {
+struct CircleColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
-struct CircleBlur : PaintProperty<float> {
+struct CircleBlur : DataDrivenPaintProperty<float, attributes::a_blur> {
static float defaultValue() { return 0; }
};
-struct CircleOpacity : PaintProperty<float> {
+struct CircleOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
@@ -37,15 +38,15 @@ struct CirclePitchScale : PaintProperty<CirclePitchScaleType> {
static CirclePitchScaleType defaultValue() { return CirclePitchScaleType::Map; }
};
-struct CircleStrokeWidth : PaintProperty<float> {
+struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width> {
static float defaultValue() { return 0; }
};
-struct CircleStrokeColor : PaintProperty<Color> {
+struct CircleStrokeColor : DataDrivenPaintProperty<Color, attributes::a_stroke_color> {
static Color defaultValue() { return Color::black(); }
};
-struct CircleStrokeOpacity : PaintProperty<float> {
+struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke_opacity> {
static float defaultValue() { return 1; }
};
diff --git a/src/mbgl/style/layers/custom_layer_impl.cpp b/src/mbgl/style/layers/custom_layer_impl.cpp
index cecd60a296..379de25e8f 100644
--- a/src/mbgl/style/layers/custom_layer_impl.cpp
+++ b/src/mbgl/style/layers/custom_layer_impl.cpp
@@ -70,7 +70,8 @@ bool CustomLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
return false;
}
-std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> CustomLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/custom_layer_impl.hpp b/src/mbgl/style/layers/custom_layer_impl.hpp
index 71fb46d0d9..33eb86828c 100644
--- a/src/mbgl/style/layers/custom_layer_impl.hpp
+++ b/src/mbgl/style/layers/custom_layer_impl.hpp
@@ -32,7 +32,7 @@ private:
void cascade(const CascadeParameters&) final {}
bool evaluate(const PropertyEvaluationParameters&) final;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const final;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const final;
CustomLayerInitializeFunction initializeFn = nullptr;
CustomLayerRenderFunction renderFn = nullptr;
diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp
index 34f0267d16..4672ede9b8 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp
@@ -80,19 +80,31 @@ void FillExtrusionLayer::setFillExtrusionOpacity(PropertyValue<float> value, con
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
+void FillExtrusionLayer::setFillExtrusionOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionOpacity>(value, klass);
+}
+
+DataDrivenPropertyValue<Color> FillExtrusionLayer::getDefaultFillExtrusionColor() {
return { Color::black() };
}
-PropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> FillExtrusionLayer::getFillExtrusionColor(const optional<std::string>& klass) const {
return impl->paint.get<FillExtrusionColor>(klass);
}
-void FillExtrusionLayer::setFillExtrusionColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void FillExtrusionLayer::setFillExtrusionColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillExtrusionColor(klass))
return;
impl->paint.set<FillExtrusionColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionColor>(value, klass);
}
PropertyValue<std::array<float, 2>> FillExtrusionLayer::getDefaultFillExtrusionTranslate() {
@@ -110,6 +122,10 @@ void FillExtrusionLayer::setFillExtrusionTranslate(PropertyValue<std::array<floa
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillExtrusionLayer::setFillExtrusionTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> FillExtrusionLayer::getDefaultFillExtrusionTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -125,6 +141,10 @@ void FillExtrusionLayer::setFillExtrusionTranslateAnchor(PropertyValue<Translate
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillExtrusionLayer::setFillExtrusionTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionTranslateAnchor>(value, klass);
+}
+
PropertyValue<std::string> FillExtrusionLayer::getDefaultFillExtrusionPattern() {
return { "" };
}
@@ -140,34 +160,54 @@ void FillExtrusionLayer::setFillExtrusionPattern(PropertyValue<std::string> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
+void FillExtrusionLayer::setFillExtrusionPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionPattern>(value, klass);
+}
+
+DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionHeight() {
return { 0 };
}
-PropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionHeight(const optional<std::string>& klass) const {
return impl->paint.get<FillExtrusionHeight>(klass);
}
-void FillExtrusionLayer::setFillExtrusionHeight(PropertyValue<float> value, const optional<std::string>& klass) {
+void FillExtrusionLayer::setFillExtrusionHeight(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillExtrusionHeight(klass))
return;
impl->paint.set<FillExtrusionHeight>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionHeightTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionHeight>(value, klass);
}
-PropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
+DataDrivenPropertyValue<float> FillExtrusionLayer::getDefaultFillExtrusionBase() {
return { 0 };
}
-PropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> FillExtrusionLayer::getFillExtrusionBase(const optional<std::string>& klass) const {
return impl->paint.get<FillExtrusionBase>(klass);
}
-void FillExtrusionLayer::setFillExtrusionBase(PropertyValue<float> value, const optional<std::string>& klass) {
+void FillExtrusionLayer::setFillExtrusionBase(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillExtrusionBase(klass))
return;
impl->paint.set<FillExtrusionBase>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillExtrusionLayer::setFillExtrusionBaseTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillExtrusionBase>(value, klass);
}
} // namespace style
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
index ebe9009312..a809820644 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp
@@ -11,7 +11,7 @@ bool FillExtrusionLayer::Impl::evaluate(const PropertyEvaluationParameters&) {
return false;
}
-std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> FillExtrusionLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
return nullptr;
}
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
index 3dd8bb270a..ed7ef747fb 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
FillExtrusionPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
index a2d01199a5..c1dd3b079d 100644
--- a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -13,7 +14,7 @@ struct FillExtrusionOpacity : PaintProperty<float> {
static float defaultValue() { return 1; }
};
-struct FillExtrusionColor : PaintProperty<Color> {
+struct FillExtrusionColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
@@ -29,11 +30,11 @@ struct FillExtrusionPattern : CrossFadedPaintProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-struct FillExtrusionHeight : PaintProperty<float> {
+struct FillExtrusionHeight : DataDrivenPaintProperty<float, attributes::a_height> {
static float defaultValue() { return 0; }
};
-struct FillExtrusionBase : PaintProperty<float> {
+struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp
index b8fa8cad8b..dfa88b5b0f 100644
--- a/src/mbgl/style/layers/fill_layer.cpp
+++ b/src/mbgl/style/layers/fill_layer.cpp
@@ -80,49 +80,77 @@ void FillLayer::setFillAntialias(PropertyValue<bool> value, const optional<std::
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> FillLayer::getDefaultFillOpacity() {
+void FillLayer::setFillAntialiasTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillAntialias>(value, klass);
+}
+
+DataDrivenPropertyValue<float> FillLayer::getDefaultFillOpacity() {
return { 1 };
}
-PropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> FillLayer::getFillOpacity(const optional<std::string>& klass) const {
return impl->paint.get<FillOpacity>(klass);
}
-void FillLayer::setFillOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void FillLayer::setFillOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getFillOpacity(klass))
return;
impl->paint.set<FillOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillOpacity>(value, klass);
}
-PropertyValue<Color> FillLayer::getDefaultFillColor() {
+DataDrivenPropertyValue<Color> FillLayer::getDefaultFillColor() {
return { Color::black() };
}
-PropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> FillLayer::getFillColor(const optional<std::string>& klass) const {
return impl->paint.get<FillColor>(klass);
}
-void FillLayer::setFillColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void FillLayer::setFillColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillColor(klass))
return;
impl->paint.set<FillColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillColor>(value, klass);
}
-PropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
+DataDrivenPropertyValue<Color> FillLayer::getDefaultFillOutlineColor() {
return { {} };
}
-PropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> FillLayer::getFillOutlineColor(const optional<std::string>& klass) const {
return impl->paint.get<FillOutlineColor>(klass);
}
-void FillLayer::setFillOutlineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void FillLayer::setFillOutlineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getFillOutlineColor(klass))
return;
impl->paint.set<FillOutlineColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void FillLayer::setFillOutlineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillOutlineColor>(value, klass);
}
PropertyValue<std::array<float, 2>> FillLayer::getDefaultFillTranslate() {
@@ -140,6 +168,10 @@ void FillLayer::setFillTranslate(PropertyValue<std::array<float, 2>> value, cons
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> FillLayer::getDefaultFillTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -155,6 +187,10 @@ void FillLayer::setFillTranslateAnchor(PropertyValue<TranslateAnchorType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillTranslateAnchor>(value, klass);
+}
+
PropertyValue<std::string> FillLayer::getDefaultFillPattern() {
return { "" };
}
@@ -170,5 +206,9 @@ void FillLayer::setFillPattern(PropertyValue<std::string> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void FillLayer::setFillPatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<FillPattern>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index 51636820f0..c7c89f8c20 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -1,5 +1,4 @@
#include <mbgl/style/layers/fill_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -15,13 +14,19 @@ void FillLayer::Impl::cascade(const CascadeParameters& parameters) {
bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
+ if (paint.unevaluated.get<FillOutlineColor>().isUndefined()) {
+ paint.evaluated.get<FillOutlineColor>() = paint.evaluated.get<FillColor>();
+ }
+
passes = RenderPass::None;
if (paint.evaluated.get<FillAntialias>()) {
passes |= RenderPass::Translucent;
}
- if (!paint.evaluated.get<FillPattern>().from.empty() || (paint.evaluated.get<FillColor>().a * paint.evaluated.get<FillOpacity>()) < 1.0f) {
+ if (!paint.unevaluated.get<FillPattern>().isUndefined()
+ || paint.evaluated.get<FillColor>().constantOr(Color()).a < 1.0f
+ || paint.evaluated.get<FillOpacity>().constantOr(0) < 1.0f) {
passes |= RenderPass::Translucent;
} else {
passes |= RenderPass::Opaque;
@@ -30,16 +35,8 @@ bool FillLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
return paint.hasTransition();
}
-std::unique_ptr<Bucket> FillLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<FillBucket>();
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> FillLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<FillBucket>(parameters, layers);
}
float FillLayer::Impl::getQueryRadius() const {
diff --git a/src/mbgl/style/layers/fill_layer_impl.hpp b/src/mbgl/style/layers/fill_layer_impl.hpp
index 28e2fa7edc..bd25a8bebf 100644
--- a/src/mbgl/style/layers/fill_layer_impl.hpp
+++ b/src/mbgl/style/layers/fill_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp
index b2d926c31e..f44a18d0e0 100644
--- a/src/mbgl/style/layers/fill_layer_properties.hpp
+++ b/src/mbgl/style/layers/fill_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -13,15 +14,15 @@ struct FillAntialias : PaintProperty<bool> {
static bool defaultValue() { return true; }
};
-struct FillOpacity : PaintProperty<float> {
+struct FillOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct FillColor : PaintProperty<Color> {
+struct FillColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
-struct FillOutlineColor : PaintProperty<Color> {
+struct FillOutlineColor : DataDrivenPaintProperty<Color, attributes::a_outline_color> {
static Color defaultValue() { return {}; }
};
diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs
index e730e3a29b..335573abf3 100644
--- a/src/mbgl/style/layers/layer.cpp.ejs
+++ b/src/mbgl/style/layers/layer.cpp.ejs
@@ -86,15 +86,15 @@ const Filter& <%- camelize(type) %>Layer::getFilter() const {
// Layout properties
<% for (const property of layoutProperties) { -%>
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
return <%- camelize(property.name) %>::defaultValue();
}
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>() const {
return impl->layout.unevaluated.get<<%- camelize(property.name) %>>();
}
-void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value) {
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value) {
if (value == get<%- camelize(property.name) %>())
return;
impl->layout.unevaluated.get<<%- camelize(property.name) %>>() = value;
@@ -104,19 +104,31 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue
// Paint properties
<% for (const property of paintProperties) { %>
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::getDefault<%- camelize(property.name) %>() {
return { <%- defaultValue(property) %> };
}
-PropertyValue<<%- propertyType(property) %>> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
+<%- propertyValueType(property) %> <%- camelize(type) %>Layer::get<%- camelize(property.name) %>(const optional<std::string>& klass) const {
return impl->paint.get<<%- camelize(property.name) %>>(klass);
}
-void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(PropertyValue<<%- propertyType(property) %>> value, const optional<std::string>& klass) {
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyValueType(property) %> value, const optional<std::string>& klass) {
if (value == get<%- camelize(property.name) %>(klass))
return;
impl->paint.set<<%- camelize(property.name) %>>(value, klass);
+<% if (isDataDriven(property)) { -%>
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+<% } else { -%>
impl->observer->onLayerPaintPropertyChanged(*this);
+<% } -%>
+}
+
+void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>Transition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<<%- camelize(property.name) %>>(value, klass);
}
<% } -%>
diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs
index d18ad44efd..2a736ca388 100644
--- a/src/mbgl/style/layers/layer_properties.hpp.ejs
+++ b/src/mbgl/style/layers/layer_properties.hpp.ejs
@@ -10,22 +10,21 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
<% for (const property of layoutProperties) { -%>
-struct <%- camelize(property.name) %> : LayoutProperty<<%- propertyType(property) %>> {
+struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) %> {
static constexpr const char * key = "<%- property.name %>";
- static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+ static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
};
<% } -%>
<% for (const property of paintProperties) { -%>
-struct <%- camelize(property.name) %> : <%
-if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') {
-%>CrossFaded<% } -%>PaintProperty<<%- propertyType(property) %>> {
- static <%- propertyType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
+struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> {
+ static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; }
};
<% } -%>
diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp
index 7f6c148cd1..eaaa0fcd45 100644
--- a/src/mbgl/style/layers/line_layer.cpp
+++ b/src/mbgl/style/layers/line_layer.cpp
@@ -122,34 +122,50 @@ void LineLayer::setLineRoundLimit(PropertyValue<float> value) {
// Paint properties
-PropertyValue<float> LineLayer::getDefaultLineOpacity() {
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineOpacity() {
return { 1 };
}
-PropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineOpacity(const optional<std::string>& klass) const {
return impl->paint.get<LineOpacity>(klass);
}
-void LineLayer::setLineOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOpacity(klass))
return;
impl->paint.set<LineOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineOpacity>(value, klass);
}
-PropertyValue<Color> LineLayer::getDefaultLineColor() {
+DataDrivenPropertyValue<Color> LineLayer::getDefaultLineColor() {
return { Color::black() };
}
-PropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> LineLayer::getLineColor(const optional<std::string>& klass) const {
return impl->paint.get<LineColor>(klass);
}
-void LineLayer::setLineColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void LineLayer::setLineColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getLineColor(klass))
return;
impl->paint.set<LineColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineColor>(value, klass);
}
PropertyValue<std::array<float, 2>> LineLayer::getDefaultLineTranslate() {
@@ -167,6 +183,10 @@ void LineLayer::setLineTranslate(PropertyValue<std::array<float, 2>> value, cons
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> LineLayer::getDefaultLineTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -182,6 +202,10 @@ void LineLayer::setLineTranslateAnchor(PropertyValue<TranslateAnchorType> value,
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineTranslateAnchor>(value, klass);
+}
+
PropertyValue<float> LineLayer::getDefaultLineWidth() {
return { 1 };
}
@@ -197,49 +221,77 @@ void LineLayer::setLineWidth(PropertyValue<float> value, const optional<std::str
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> LineLayer::getDefaultLineGapWidth() {
+void LineLayer::setLineWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineGapWidth() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineGapWidth(const optional<std::string>& klass) const {
return impl->paint.get<LineGapWidth>(klass);
}
-void LineLayer::setLineGapWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineGapWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineGapWidth(klass))
return;
impl->paint.set<LineGapWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> LineLayer::getDefaultLineOffset() {
+void LineLayer::setLineGapWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineGapWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineOffset() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineOffset(const optional<std::string>& klass) const {
return impl->paint.get<LineOffset>(klass);
}
-void LineLayer::setLineOffset(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineOffset(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineOffset(klass))
return;
impl->paint.set<LineOffset>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> LineLayer::getDefaultLineBlur() {
+void LineLayer::setLineOffsetTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineOffset>(value, klass);
+}
+
+DataDrivenPropertyValue<float> LineLayer::getDefaultLineBlur() {
return { 0 };
}
-PropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> LineLayer::getLineBlur(const optional<std::string>& klass) const {
return impl->paint.get<LineBlur>(klass);
}
-void LineLayer::setLineBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void LineLayer::setLineBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getLineBlur(klass))
return;
impl->paint.set<LineBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void LineLayer::setLineBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineBlur>(value, klass);
}
PropertyValue<std::vector<float>> LineLayer::getDefaultLineDasharray() {
@@ -257,6 +309,10 @@ void LineLayer::setLineDasharray(PropertyValue<std::vector<float>> value, const
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLineDasharrayTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LineDasharray>(value, klass);
+}
+
PropertyValue<std::string> LineLayer::getDefaultLinePattern() {
return { "" };
}
@@ -272,5 +328,9 @@ void LineLayer::setLinePattern(PropertyValue<std::string> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void LineLayer::setLinePatternTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<LinePattern>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp
index 477579a43c..ef0131e3d5 100644
--- a/src/mbgl/style/layers/line_layer_impl.cpp
+++ b/src/mbgl/style/layers/line_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/line_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/util/math.hpp>
@@ -20,31 +20,25 @@ bool LineLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters) {
paint.evaluate(parameters);
- passes = (paint.evaluated.get<LineOpacity>() > 0 && paint.evaluated.get<LineColor>().a > 0 && paint.evaluated.get<LineWidth>() > 0)
+ passes = (paint.evaluated.get<LineOpacity>().constantOr(1.0) > 0
+ && paint.evaluated.get<LineColor>().constantOr(Color::black()).a > 0
+ && paint.evaluated.get<LineWidth>() > 0)
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> LineLayer::Impl::createBucket(BucketParameters& parameters, const GeometryTileLayer& layer) const {
- auto bucket = std::make_unique<LineBucket>(parameters.tileID.overscaleFactor());
-
- bucket->layout = layout.evaluate(PropertyEvaluationParameters(parameters.tileID.overscaledZ));
-
- parameters.eachFilteredFeature(filter, layer, [&] (const auto& feature, std::size_t index, const std::string& layerName) {
- auto geometries = feature.getGeometries();
- bucket->addGeometry(geometries);
- parameters.featureIndex.insert(geometries, index, layerName, id);
- });
-
- return std::move(bucket);
+std::unique_ptr<Bucket> LineLayer::Impl::createBucket(const BucketParameters& parameters, const std::vector<const Layer*>& layers) const {
+ return std::make_unique<LineBucket>(parameters, layers, layout);
}
float LineLayer::Impl::getLineWidth() const {
- if (paint.evaluated.get<LineGapWidth>() > 0) {
- return paint.evaluated.get<LineGapWidth>() + 2 * paint.evaluated.get<LineWidth>();
+ float lineWidth = paint.evaluated.get<LineWidth>();
+ float gapWidth = paint.evaluated.get<LineGapWidth>().constantOr(0);
+ if (gapWidth) {
+ return gapWidth + 2 * lineWidth;
} else {
- return paint.evaluated.get<LineWidth>();
+ return lineWidth;
}
}
@@ -80,7 +74,8 @@ optional<GeometryCollection> offsetLine(const GeometryCollection& rings, const d
float LineLayer::Impl::getQueryRadius() const {
const std::array<float, 2>& translate = paint.evaluated.get<LineTranslate>();
- return getLineWidth() / 2.0 + std::abs(paint.evaluated.get<LineOffset>()) + util::length(translate[0], translate[1]);
+ auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue());
+ return getLineWidth() / 2.0 + std::abs(offset) + util::length(translate[0], translate[1]);
}
bool LineLayer::Impl::queryIntersectsGeometry(
@@ -93,7 +88,9 @@ bool LineLayer::Impl::queryIntersectsGeometry(
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry, paint.evaluated.get<LineTranslate>(), paint.evaluated.get<LineTranslateAnchor>(), bearing, pixelsToTileUnits);
- auto offsetGeometry = offsetLine(geometry, paint.evaluated.get<LineOffset>() * pixelsToTileUnits);
+
+ auto offset = paint.evaluated.get<LineOffset>().constantOr(LineOffset::defaultValue());
+ auto offsetGeometry = offsetLine(geometry, offset * pixelsToTileUnits);
return util::polygonIntersectsBufferedMultiLine(
translatedQueryGeometry.value_or(queryGeometry),
diff --git a/src/mbgl/style/layers/line_layer_impl.hpp b/src/mbgl/style/layers/line_layer_impl.hpp
index 1955c019af..67e793f2ea 100644
--- a/src/mbgl/style/layers/line_layer_impl.hpp
+++ b/src/mbgl/style/layers/line_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
float getQueryRadius() const override;
bool queryIntersectsGeometry(
diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp
index 2ea7f6b125..724026e3a6 100644
--- a/src/mbgl/style/layers/line_layer_properties.hpp
+++ b/src/mbgl/style/layers/line_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -29,11 +30,11 @@ struct LineRoundLimit : LayoutProperty<float> {
static float defaultValue() { return 1; }
};
-struct LineOpacity : PaintProperty<float> {
+struct LineOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct LineColor : PaintProperty<Color> {
+struct LineColor : DataDrivenPaintProperty<Color, attributes::a_color> {
static Color defaultValue() { return Color::black(); }
};
@@ -49,15 +50,15 @@ struct LineWidth : PaintProperty<float> {
static float defaultValue() { return 1; }
};
-struct LineGapWidth : PaintProperty<float> {
+struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gap_width> {
static float defaultValue() { return 0; }
};
-struct LineOffset : PaintProperty<float> {
+struct LineOffset : DataDrivenPaintProperty<float, attributes::a_offset<1>> {
static float defaultValue() { return 0; }
};
-struct LineBlur : PaintProperty<float> {
+struct LineBlur : DataDrivenPaintProperty<float, attributes::a_blur> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp
index 0fda27f0dc..2108a5c49f 100644
--- a/src/mbgl/style/layers/raster_layer.cpp
+++ b/src/mbgl/style/layers/raster_layer.cpp
@@ -62,6 +62,10 @@ void RasterLayer::setRasterOpacity(PropertyValue<float> value, const optional<st
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterOpacity>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterHueRotate() {
return { 0 };
}
@@ -77,6 +81,10 @@ void RasterLayer::setRasterHueRotate(PropertyValue<float> value, const optional<
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterHueRotateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterHueRotate>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMin() {
return { 0 };
}
@@ -92,6 +100,10 @@ void RasterLayer::setRasterBrightnessMin(PropertyValue<float> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterBrightnessMinTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterBrightnessMin>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterBrightnessMax() {
return { 1 };
}
@@ -107,6 +119,10 @@ void RasterLayer::setRasterBrightnessMax(PropertyValue<float> value, const optio
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterBrightnessMaxTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterBrightnessMax>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterSaturation() {
return { 0 };
}
@@ -122,6 +138,10 @@ void RasterLayer::setRasterSaturation(PropertyValue<float> value, const optional
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterSaturationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterSaturation>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterContrast() {
return { 0 };
}
@@ -137,6 +157,10 @@ void RasterLayer::setRasterContrast(PropertyValue<float> value, const optional<s
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterContrastTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterContrast>(value, klass);
+}
+
PropertyValue<float> RasterLayer::getDefaultRasterFadeDuration() {
return { 300 };
}
@@ -152,5 +176,9 @@ void RasterLayer::setRasterFadeDuration(PropertyValue<float> value, const option
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void RasterLayer::setRasterFadeDurationTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<RasterFadeDuration>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/raster_layer_impl.cpp b/src/mbgl/style/layers/raster_layer_impl.cpp
index a78614aee9..a667ccb5a8 100644
--- a/src/mbgl/style/layers/raster_layer_impl.cpp
+++ b/src/mbgl/style/layers/raster_layer_impl.cpp
@@ -16,7 +16,8 @@ bool RasterLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters)
return paint.hasTransition();
}
-std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> RasterLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
+ assert(false);
return nullptr;
}
diff --git a/src/mbgl/style/layers/raster_layer_impl.hpp b/src/mbgl/style/layers/raster_layer_impl.hpp
index 8e69c21ca8..42985ce0f1 100644
--- a/src/mbgl/style/layers/raster_layer_impl.hpp
+++ b/src/mbgl/style/layers/raster_layer_impl.hpp
@@ -16,7 +16,7 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
RasterPaintProperties paint;
};
diff --git a/src/mbgl/style/layers/raster_layer_properties.hpp b/src/mbgl/style/layers/raster_layer_properties.hpp
index caa6d0c58d..219fe34d8c 100644
--- a/src/mbgl/style/layers/raster_layer_properties.hpp
+++ b/src/mbgl/style/layers/raster_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp
index c9014e7ee7..d85b8c00e6 100644
--- a/src/mbgl/style/layers/symbol_layer.cpp
+++ b/src/mbgl/style/layers/symbol_layer.cpp
@@ -217,15 +217,15 @@ void SymbolLayer::setIconImage(PropertyValue<std::string> value) {
impl->layout.unevaluated.get<IconImage>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-image");
}
-PropertyValue<float> SymbolLayer::getDefaultIconRotate() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconRotate() {
return IconRotate::defaultValue();
}
-PropertyValue<float> SymbolLayer::getIconRotate() const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconRotate() const {
return impl->layout.unevaluated.get<IconRotate>();
}
-void SymbolLayer::setIconRotate(PropertyValue<float> value) {
+void SymbolLayer::setIconRotate(DataDrivenPropertyValue<float> value) {
if (value == getIconRotate())
return;
impl->layout.unevaluated.get<IconRotate>() = value;
@@ -259,15 +259,15 @@ void SymbolLayer::setIconKeepUpright(PropertyValue<bool> value) {
impl->layout.unevaluated.get<IconKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "icon-keep-upright");
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
+DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconOffset() {
return IconOffset::defaultValue();
}
-PropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
+DataDrivenPropertyValue<std::array<float, 2>> SymbolLayer::getIconOffset() const {
return impl->layout.unevaluated.get<IconOffset>();
}
-void SymbolLayer::setIconOffset(PropertyValue<std::array<float, 2>> value) {
+void SymbolLayer::setIconOffset(DataDrivenPropertyValue<std::array<float, 2>> value) {
if (value == getIconOffset())
return;
impl->layout.unevaluated.get<IconOffset>() = value;
@@ -301,15 +301,15 @@ void SymbolLayer::setTextRotationAlignment(PropertyValue<AlignmentType> value) {
impl->layout.unevaluated.get<TextRotationAlignment>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-rotation-alignment");
}
-PropertyValue<std::string> SymbolLayer::getDefaultTextField() {
+DataDrivenPropertyValue<std::string> SymbolLayer::getDefaultTextField() {
return TextField::defaultValue();
}
-PropertyValue<std::string> SymbolLayer::getTextField() const {
+DataDrivenPropertyValue<std::string> SymbolLayer::getTextField() const {
return impl->layout.unevaluated.get<TextField>();
}
-void SymbolLayer::setTextField(PropertyValue<std::string> value) {
+void SymbolLayer::setTextField(DataDrivenPropertyValue<std::string> value) {
if (value == getTextField())
return;
impl->layout.unevaluated.get<TextField>() = value;
@@ -469,15 +469,15 @@ void SymbolLayer::setTextKeepUpright(PropertyValue<bool> value) {
impl->layout.unevaluated.get<TextKeepUpright>() = value;
impl->observer->onLayerLayoutPropertyChanged(*this, "text-keep-upright");
}
-PropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
+DataDrivenPropertyValue<TextTransformType> SymbolLayer::getDefaultTextTransform() {
return TextTransform::defaultValue();
}
-PropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
+DataDrivenPropertyValue<TextTransformType> SymbolLayer::getTextTransform() const {
return impl->layout.unevaluated.get<TextTransform>();
}
-void SymbolLayer::setTextTransform(PropertyValue<TextTransformType> value) {
+void SymbolLayer::setTextTransform(DataDrivenPropertyValue<TextTransformType> value) {
if (value == getTextTransform())
return;
impl->layout.unevaluated.get<TextTransform>() = value;
@@ -542,79 +542,119 @@ void SymbolLayer::setTextOptional(PropertyValue<bool> value) {
// Paint properties
-PropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconOpacity() {
return { 1 };
}
-PropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconOpacity(const optional<std::string>& klass) const {
return impl->paint.get<IconOpacity>(klass);
}
-void SymbolLayer::setIconOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconOpacity(klass))
return;
impl->paint.set<IconOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconOpacity>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultIconColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconColor() {
return { Color::black() };
}
-PropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getIconColor(const optional<std::string>& klass) const {
return impl->paint.get<IconColor>(klass);
}
-void SymbolLayer::setIconColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconColor(klass))
return;
impl->paint.set<IconColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconColor>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultIconHaloColor() {
return { {} };
}
-PropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getIconHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloColor>(klass);
}
-void SymbolLayer::setIconHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getIconHaloColor(klass))
return;
impl->paint.set<IconHaloColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
+void SymbolLayer::setIconHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloWidth() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloWidth>(klass);
}
-void SymbolLayer::setIconHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloWidth(klass))
return;
impl->paint.set<IconHaloWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
+void SymbolLayer::setIconHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultIconHaloBlur() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getIconHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<IconHaloBlur>(klass);
}
-void SymbolLayer::setIconHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setIconHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getIconHaloBlur(klass))
return;
impl->paint.set<IconHaloBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setIconHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconHaloBlur>(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultIconTranslate() {
@@ -632,6 +672,10 @@ void SymbolLayer::setIconTranslate(PropertyValue<std::array<float, 2>> value, co
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setIconTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultIconTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -647,79 +691,123 @@ void SymbolLayer::setIconTranslateAnchor(PropertyValue<TranslateAnchorType> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
-PropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
+void SymbolLayer::setIconTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<IconTranslateAnchor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextOpacity() {
return { 1 };
}
-PropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextOpacity(const optional<std::string>& klass) const {
return impl->paint.get<TextOpacity>(klass);
}
-void SymbolLayer::setTextOpacity(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextOpacity(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextOpacity(klass))
return;
impl->paint.set<TextOpacity>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextOpacityTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextOpacity>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultTextColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextColor() {
return { Color::black() };
}
-PropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getTextColor(const optional<std::string>& klass) const {
return impl->paint.get<TextColor>(klass);
}
-void SymbolLayer::setTextColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextColor(klass))
return;
impl->paint.set<TextColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextColor>(value, klass);
}
-PropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
+DataDrivenPropertyValue<Color> SymbolLayer::getDefaultTextHaloColor() {
return { {} };
}
-PropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<Color> SymbolLayer::getTextHaloColor(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloColor>(klass);
}
-void SymbolLayer::setTextHaloColor(PropertyValue<Color> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloColor(DataDrivenPropertyValue<Color> value, const optional<std::string>& klass) {
if (value == getTextHaloColor(klass))
return;
impl->paint.set<TextHaloColor>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
+void SymbolLayer::setTextHaloColorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloColor>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloWidth() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloWidth(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloWidth>(klass);
}
-void SymbolLayer::setTextHaloWidth(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloWidth(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloWidth(klass))
return;
impl->paint.set<TextHaloWidth>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
}
-PropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
+void SymbolLayer::setTextHaloWidthTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloWidth>(value, klass);
+}
+
+DataDrivenPropertyValue<float> SymbolLayer::getDefaultTextHaloBlur() {
return { 0 };
}
-PropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
+DataDrivenPropertyValue<float> SymbolLayer::getTextHaloBlur(const optional<std::string>& klass) const {
return impl->paint.get<TextHaloBlur>(klass);
}
-void SymbolLayer::setTextHaloBlur(PropertyValue<float> value, const optional<std::string>& klass) {
+void SymbolLayer::setTextHaloBlur(DataDrivenPropertyValue<float> value, const optional<std::string>& klass) {
if (value == getTextHaloBlur(klass))
return;
impl->paint.set<TextHaloBlur>(value, klass);
- impl->observer->onLayerPaintPropertyChanged(*this);
+ if (value.isDataDriven()) {
+ impl->observer->onLayerDataDrivenPaintPropertyChanged(*this);
+ } else {
+ impl->observer->onLayerPaintPropertyChanged(*this);
+ }
+}
+
+void SymbolLayer::setTextHaloBlurTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextHaloBlur>(value, klass);
}
PropertyValue<std::array<float, 2>> SymbolLayer::getDefaultTextTranslate() {
@@ -737,6 +825,10 @@ void SymbolLayer::setTextTranslate(PropertyValue<std::array<float, 2>> value, co
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setTextTranslateTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextTranslate>(value, klass);
+}
+
PropertyValue<TranslateAnchorType> SymbolLayer::getDefaultTextTranslateAnchor() {
return { TranslateAnchorType::Map };
}
@@ -752,5 +844,9 @@ void SymbolLayer::setTextTranslateAnchor(PropertyValue<TranslateAnchorType> valu
impl->observer->onLayerPaintPropertyChanged(*this);
}
+void SymbolLayer::setTextTranslateAnchorTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ impl->paint.setTransition<TextTranslateAnchor>(value, klass);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp
index f058598f5f..ff59b14d65 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.cpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.cpp
@@ -1,5 +1,5 @@
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/style/bucket_parameters.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/renderer/bucket.hpp>
@@ -16,77 +16,70 @@ bool SymbolLayer::Impl::evaluate(const PropertyEvaluationParameters& parameters)
// text-size and icon-size are layout properties but they also need to be evaluated as paint properties:
iconSize = layout.evaluate<IconSize>(parameters);
textSize = layout.evaluate<TextSize>(parameters);
-
- passes = ((paint.evaluated.get<IconOpacity>() > 0 && (paint.evaluated.get<IconColor>().a > 0 || paint.evaluated.get<IconHaloColor>().a > 0) && iconSize > 0)
- || (paint.evaluated.get<TextOpacity>() > 0 && (paint.evaluated.get<TextColor>().a > 0 || paint.evaluated.get<TextHaloColor>().a > 0) && textSize > 0))
+
+ auto hasIconOpacity = paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0;
+ auto hasTextOpacity = paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0 ||
+ paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0;
+
+ passes = ((paint.evaluated.get<IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
+ || (paint.evaluated.get<TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
? RenderPass::Translucent : RenderPass::None;
return paint.hasTransition();
}
-std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(BucketParameters&, const GeometryTileLayer&) const {
+std::unique_ptr<Bucket> SymbolLayer::Impl::createBucket(const BucketParameters&, const std::vector<const Layer*>&) const {
assert(false); // Should be calling createLayout() instead.
return nullptr;
}
-std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(BucketParameters& parameters,
- const GeometryTileLayer& layer,
- std::vector<std::string> group) const {
- PropertyEvaluationParameters p(parameters.tileID.overscaledZ);
- SymbolLayoutProperties::Evaluated evaluated = layout.evaluate(p);
-
- if (evaluated.get<IconRotationAlignment>() == AlignmentType::Auto) {
- if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
- evaluated.get<IconRotationAlignment>() = AlignmentType::Map;
- } else {
- evaluated.get<IconRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- if (evaluated.get<TextRotationAlignment>() == AlignmentType::Auto) {
- if (evaluated.get<SymbolPlacement>() == SymbolPlacementType::Line) {
- evaluated.get<TextRotationAlignment>() = AlignmentType::Map;
- } else {
- evaluated.get<TextRotationAlignment>() = AlignmentType::Viewport;
- }
- }
-
- // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment`
- if (evaluated.get<TextPitchAlignment>() == AlignmentType::Auto) {
- evaluated.get<TextPitchAlignment>() = evaluated.get<TextRotationAlignment>();
- }
-
- float textMaxSize = layout.evaluate<TextSize>(PropertyEvaluationParameters(18));
-
- evaluated.get<IconSize>() = layout.evaluate<IconSize>(PropertyEvaluationParameters(p.z + 1));
- evaluated.get<TextSize>() = layout.evaluate<TextSize>(PropertyEvaluationParameters(p.z + 1));
-
- return std::make_unique<SymbolLayout>(std::move(group),
- layer.getName(),
- parameters.tileID.overscaleFactor(),
- parameters.tileID.overscaledZ,
- parameters.mode,
+std::unique_ptr<SymbolLayout> SymbolLayer::Impl::createLayout(const BucketParameters& parameters,
+ const std::vector<const Layer*>& group,
+ const GeometryTileLayer& layer) const {
+ return std::make_unique<SymbolLayout>(parameters,
+ group,
layer,
- filter,
- evaluated,
- textMaxSize,
*spriteAtlas);
}
-SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
- return SymbolPropertyValues {
- layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
- layout_.get<IconRotationAlignment>(),
- layout_.get<IconSize>(),
+IconPaintProperties::Evaluated SymbolLayer::Impl::iconPaintProperties() const {
+ return IconPaintProperties::Evaluated {
paint.evaluated.get<IconOpacity>(),
paint.evaluated.get<IconColor>(),
paint.evaluated.get<IconHaloColor>(),
paint.evaluated.get<IconHaloWidth>(),
paint.evaluated.get<IconHaloBlur>(),
paint.evaluated.get<IconTranslate>(),
+ paint.evaluated.get<IconTranslateAnchor>()
+ };
+}
+
+TextPaintProperties::Evaluated SymbolLayer::Impl::textPaintProperties() const {
+ return TextPaintProperties::Evaluated {
+ paint.evaluated.get<TextOpacity>(),
+ paint.evaluated.get<TextColor>(),
+ paint.evaluated.get<TextHaloColor>(),
+ paint.evaluated.get<TextHaloWidth>(),
+ paint.evaluated.get<TextHaloBlur>(),
+ paint.evaluated.get<TextTranslate>(),
+ paint.evaluated.get<TextTranslateAnchor>()
+ };
+}
+
+
+SymbolPropertyValues SymbolLayer::Impl::iconPropertyValues(const SymbolLayoutProperties::Evaluated& layout_) const {
+ return SymbolPropertyValues {
+ layout_.get<IconRotationAlignment>(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment
+ layout_.get<IconRotationAlignment>(),
+ layout_.get<IconSize>(),
+ paint.evaluated.get<IconTranslate>(),
paint.evaluated.get<IconTranslateAnchor>(),
iconSize,
- 1.0f
+ 1.0f,
+ paint.evaluated.get<IconHaloColor>().constantOr(Color::black()).a > 0 &&
+ paint.evaluated.get<IconHaloWidth>().constantOr(1),
+ paint.evaluated.get<IconColor>().constantOr(Color::black()).a > 0
};
}
@@ -95,15 +88,13 @@ SymbolPropertyValues SymbolLayer::Impl::textPropertyValues(const SymbolLayoutPro
layout_.get<TextPitchAlignment>(),
layout_.get<TextRotationAlignment>(),
layout_.get<TextSize>(),
- paint.evaluated.get<TextOpacity>(),
- paint.evaluated.get<TextColor>(),
- paint.evaluated.get<TextHaloColor>(),
- paint.evaluated.get<TextHaloWidth>(),
- paint.evaluated.get<TextHaloBlur>(),
paint.evaluated.get<TextTranslate>(),
paint.evaluated.get<TextTranslateAnchor>(),
textSize,
- 24.0f
+ 24.0f,
+ paint.evaluated.get<TextHaloColor>().constantOr(Color::black()).a > 0 &&
+ paint.evaluated.get<TextHaloWidth>().constantOr(1),
+ paint.evaluated.get<TextColor>().constantOr(Color::black()).a > 0
};
}
diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp
index db18da07e2..1e9f05e4c7 100644
--- a/src/mbgl/style/layers/symbol_layer_impl.hpp
+++ b/src/mbgl/style/layers/symbol_layer_impl.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <mbgl/util/variant.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
@@ -10,6 +11,30 @@ class SpriteAtlas;
class SymbolLayout;
namespace style {
+
+
+// {icon,text}-specific paint-property packs for use in the symbol Programs.
+// Since each program deals either with icons or text, using a smaller property set
+// lets us avoid unnecessarily binding attributes for properties the program wouldn't use.
+class IconPaintProperties : public PaintProperties<
+ IconOpacity,
+ IconColor,
+ IconHaloColor,
+ IconHaloWidth,
+ IconHaloBlur,
+ IconTranslate,
+ IconTranslateAnchor
+> {};
+
+class TextPaintProperties : public PaintProperties<
+ TextOpacity,
+ TextColor,
+ TextHaloColor,
+ TextHaloWidth,
+ TextHaloBlur,
+ TextTranslate,
+ TextTranslateAnchor
+> {};
// Repackaging evaluated values from SymbolLayoutProperties + SymbolPaintProperties
// for genericity over icons vs. text.
@@ -21,24 +46,14 @@ public:
float layoutSize;
// Paint
- float opacity;
- Color color;
- Color haloColor;
- float haloWidth;
- float haloBlur;
std::array<float, 2> translate;
TranslateAnchorType translateAnchor;
float paintSize;
float sdfScale; // Constant (1.0 or 24.0)
-
- bool hasHalo() const {
- return haloColor.a > 0.0f && haloWidth > 0.0f;
- }
-
- bool hasForeground() const {
- return color.a > 0.0f;
- }
+
+ bool hasHalo;
+ bool hasFill;
};
class SymbolLayer::Impl : public Layer::Impl {
@@ -50,10 +65,13 @@ public:
void cascade(const CascadeParameters&) override;
bool evaluate(const PropertyEvaluationParameters&) override;
- std::unique_ptr<Bucket> createBucket(BucketParameters&, const GeometryTileLayer&) const override;
- std::unique_ptr<SymbolLayout> createLayout(BucketParameters&, const GeometryTileLayer&,
- std::vector<std::string>) const;
+ std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const Layer*>&) const override;
+ std::unique_ptr<SymbolLayout> createLayout(const BucketParameters&, const std::vector<const Layer*>&,
+ const GeometryTileLayer&) const;
+ IconPaintProperties::Evaluated iconPaintProperties() const;
+ TextPaintProperties::Evaluated textPaintProperties() const;
+
SymbolPropertyValues iconPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
SymbolPropertyValues textPropertyValues(const SymbolLayoutProperties::Evaluated&) const;
diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp
index f5fd6ce3df..f2b7bfa00f 100644
--- a/src/mbgl/style/layers/symbol_layer_properties.hpp
+++ b/src/mbgl/style/layers/symbol_layer_properties.hpp
@@ -5,6 +5,7 @@
#include <mbgl/style/types.hpp>
#include <mbgl/style/layout_property.hpp>
#include <mbgl/style/paint_property.hpp>
+#include <mbgl/programs/attributes.hpp>
namespace mbgl {
namespace style {
@@ -64,7 +65,7 @@ struct IconImage : LayoutProperty<std::string> {
static std::string defaultValue() { return ""; }
};
-struct IconRotate : LayoutProperty<float> {
+struct IconRotate : DataDrivenLayoutProperty<float> {
static constexpr const char * key = "icon-rotate";
static float defaultValue() { return 0; }
};
@@ -79,7 +80,7 @@ struct IconKeepUpright : LayoutProperty<bool> {
static bool defaultValue() { return false; }
};
-struct IconOffset : LayoutProperty<std::array<float, 2>> {
+struct IconOffset : DataDrivenLayoutProperty<std::array<float, 2>> {
static constexpr const char * key = "icon-offset";
static std::array<float, 2> defaultValue() { return {{ 0, 0 }}; }
};
@@ -94,7 +95,7 @@ struct TextRotationAlignment : LayoutProperty<AlignmentType> {
static AlignmentType defaultValue() { return AlignmentType::Auto; }
};
-struct TextField : LayoutProperty<std::string> {
+struct TextField : DataDrivenLayoutProperty<std::string> {
static constexpr const char * key = "text-field";
static std::string defaultValue() { return ""; }
};
@@ -154,7 +155,7 @@ struct TextKeepUpright : LayoutProperty<bool> {
static bool defaultValue() { return true; }
};
-struct TextTransform : LayoutProperty<TextTransformType> {
+struct TextTransform : DataDrivenLayoutProperty<TextTransformType> {
static constexpr const char * key = "text-transform";
static TextTransformType defaultValue() { return TextTransformType::None; }
};
@@ -179,23 +180,23 @@ struct TextOptional : LayoutProperty<bool> {
static bool defaultValue() { return false; }
};
-struct IconOpacity : PaintProperty<float> {
+struct IconOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct IconColor : PaintProperty<Color> {
+struct IconColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
-struct IconHaloColor : PaintProperty<Color> {
+struct IconHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
-struct IconHaloWidth : PaintProperty<float> {
+struct IconHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
-struct IconHaloBlur : PaintProperty<float> {
+struct IconHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};
@@ -207,23 +208,23 @@ struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> {
static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; }
};
-struct TextOpacity : PaintProperty<float> {
+struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity> {
static float defaultValue() { return 1; }
};
-struct TextColor : PaintProperty<Color> {
+struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color> {
static Color defaultValue() { return Color::black(); }
};
-struct TextHaloColor : PaintProperty<Color> {
+struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color> {
static Color defaultValue() { return {}; }
};
-struct TextHaloWidth : PaintProperty<float> {
+struct TextHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width> {
static float defaultValue() { return 0; }
};
-struct TextHaloBlur : PaintProperty<float> {
+struct TextHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur> {
static float defaultValue() { return 0; }
};
diff --git a/src/mbgl/style/layout_property.hpp b/src/mbgl/style/layout_property.hpp
index 6ea06ce556..25cff4b92d 100644
--- a/src/mbgl/style/layout_property.hpp
+++ b/src/mbgl/style/layout_property.hpp
@@ -1,6 +1,9 @@
#pragma once
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/style/property_evaluator.hpp>
+#include <mbgl/style/data_driven_property_evaluator.hpp>
#include <mbgl/util/indexed_tuple.hpp>
namespace mbgl {
@@ -11,9 +14,19 @@ class PropertyEvaluationParameters;
template <class T>
class LayoutProperty {
public:
- using EvaluatorType = PropertyEvaluator<T>;
using UnevaluatedType = PropertyValue<T>;
+ using EvaluatorType = PropertyEvaluator<T>;
using EvaluatedType = T;
+ using Type = T;
+};
+
+template <class T>
+class DataDrivenLayoutProperty {
+public:
+ using UnevaluatedType = DataDrivenPropertyValue<T>;
+ using EvaluatorType = DataDrivenPropertyEvaluator<T>;
+ using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ using Type = T;
};
template <class... Ps>
@@ -29,6 +42,15 @@ public:
class Evaluated : public Tuple<EvaluatedTypes> {
public:
using Tuple<EvaluatedTypes>::Tuple;
+
+ template <class P>
+ typename P::Type evaluate(float z, const GeometryTileFeature& feature) const {
+ using T = typename P::Type;
+ return this->template get<P>().match(
+ [&] (const T& t) { return t; },
+ [&] (const SourceFunction<T>& t) { return t.evaluate(feature, P::defaultValue()); },
+ [&] (const CompositeFunction<T>& t) { return t.evaluate(z, feature, P::defaultValue()); });
+ }
};
class Unevaluated : public Tuple<UnevaluatedTypes> {
diff --git a/src/mbgl/style/paint_property.hpp b/src/mbgl/style/paint_property.hpp
index 7b56f6415d..1fa2390f33 100644
--- a/src/mbgl/style/paint_property.hpp
+++ b/src/mbgl/style/paint_property.hpp
@@ -1,11 +1,15 @@
#pragma once
#include <mbgl/style/class_dictionary.hpp>
+#include <mbgl/style/property_value.hpp>
+#include <mbgl/style/data_driven_property_value.hpp>
#include <mbgl/style/property_evaluator.hpp>
#include <mbgl/style/cross_faded_property_evaluator.hpp>
+#include <mbgl/style/data_driven_property_evaluator.hpp>
+#include <mbgl/style/property_evaluation_parameters.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/cascade_parameters.hpp>
-#include <mbgl/style/property_evaluation_parameters.hpp>
+#include <mbgl/style/paint_property_binder.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/indexed_tuple.hpp>
@@ -15,17 +19,18 @@
#include <utility>
namespace mbgl {
+
+class GeometryTileFeature;
+
namespace style {
-template <class T, class Evaluator>
+template <class Value>
class UnevaluatedPaintProperty {
public:
- using Result = typename Evaluator::ResultType;
-
UnevaluatedPaintProperty() = default;
- UnevaluatedPaintProperty(PropertyValue<T> value_,
- UnevaluatedPaintProperty<T, Evaluator> prior_,
+ UnevaluatedPaintProperty(Value value_,
+ UnevaluatedPaintProperty<Value> prior_,
TransitionOptions transition,
TimePoint now)
: begin(now + transition.delay.value_or(Duration::zero())),
@@ -36,22 +41,23 @@ public:
}
}
- Result evaluate(const PropertyEvaluationParameters& parameters, T defaultValue) {
- Result finalValue = value.evaluate(Evaluator(parameters, defaultValue));
+ template <class Evaluator>
+ auto evaluate(const Evaluator& evaluator, TimePoint now) {
+ auto finalValue = value.evaluate(evaluator);
if (!prior) {
// No prior value.
return finalValue;
- } else if (parameters.now >= end) {
+ } else if (now >= end) {
// Transition from prior value is now complete.
prior = {};
return finalValue;
- } else if (parameters.now < begin) {
+ } else if (now < begin) {
// Transition hasn't started yet.
- return prior->get().evaluate(parameters, defaultValue);
+ return prior->get().evaluate(evaluator, now);
} else {
// Interpolate between recursively-calculated prior value and final.
- float t = std::chrono::duration<float>(parameters.now - begin) / (end - begin);
- return util::interpolate(prior->get().evaluate(parameters, defaultValue), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
+ float t = std::chrono::duration<float>(now - begin) / (end - begin);
+ return util::interpolate(prior->get().evaluate(evaluator, now), finalValue, util::DEFAULT_TRANSITION_EASE.solve(t, 0.001));
}
}
@@ -63,30 +69,40 @@ public:
return value.isUndefined();
}
+ const Value& getValue() const {
+ return value;
+ }
+
private:
- optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<T, Evaluator>>> prior;
+ optional<mapbox::util::recursive_wrapper<UnevaluatedPaintProperty<Value>>> prior;
TimePoint begin;
TimePoint end;
- PropertyValue<T> value;
+ Value value;
};
-template <class T>
+template <class Value>
class CascadingPaintProperty {
public:
bool isUndefined() const {
return values.find(ClassID::Default) == values.end();
}
- const PropertyValue<T>& get(const optional<std::string>& klass) const {
- static const PropertyValue<T> staticValue;
+ const Value& get(const optional<std::string>& klass) const {
+ static const Value staticValue{};
const auto it = values.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default);
return it == values.end() ? staticValue : it->second;
}
- void set(const PropertyValue<T>& value_, const optional<std::string>& klass) {
+ void set(const Value& value_, const optional<std::string>& klass) {
values[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = value_;
}
+ const TransitionOptions& getTransition(const optional<std::string>& klass) const {
+ static const TransitionOptions staticValue{};
+ const auto it = transitions.find(klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default);
+ return it == transitions.end() ? staticValue : it->second;
+ }
+
void setTransition(const TransitionOptions& transition, const optional<std::string>& klass) {
transitions[klass ? ClassDictionary::Get().lookup(*klass) : ClassID::Default] = transition;
}
@@ -94,7 +110,7 @@ public:
template <class UnevaluatedPaintProperty>
UnevaluatedPaintProperty cascade(const CascadeParameters& params, UnevaluatedPaintProperty prior) const {
TransitionOptions transition;
- PropertyValue<T> value;
+ Value value;
for (const auto classID : params.classes) {
if (values.find(classID) != values.end()) {
@@ -117,7 +133,7 @@ public:
}
private:
- std::unordered_map<ClassID, PropertyValue<T>> values;
+ std::unordered_map<ClassID, Value> values;
std::unordered_map<ClassID, TransitionOptions> transitions;
};
@@ -125,26 +141,48 @@ template <class T>
class PaintProperty {
public:
using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
using EvaluatorType = PropertyEvaluator<T>;
- using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
using EvaluatedType = T;
+ static constexpr bool IsDataDriven = false;
+};
+
+template <class T, class A>
+class DataDrivenPaintProperty {
+public:
+ using ValueType = DataDrivenPropertyValue<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
+ using EvaluatorType = DataDrivenPropertyEvaluator<T>;
+ using EvaluatedType = PossiblyEvaluatedPropertyValue<T>;
+ static constexpr bool IsDataDriven = true;
+
+ using Type = T;
+ using Attribute = A;
};
template <class T>
class CrossFadedPaintProperty {
public:
using ValueType = PropertyValue<T>;
- using CascadingType = CascadingPaintProperty<T>;
+ using CascadingType = CascadingPaintProperty<ValueType>;
+ using UnevaluatedType = UnevaluatedPaintProperty<ValueType>;
using EvaluatorType = CrossFadedPropertyEvaluator<T>;
- using UnevaluatedType = UnevaluatedPaintProperty<T, EvaluatorType>;
using EvaluatedType = Faded<T>;
+ static constexpr bool IsDataDriven = false;
};
+template <class P>
+struct IsDataDriven : std::integral_constant<bool, P::IsDataDriven> {};
+
template <class... Ps>
class PaintProperties {
public:
using Properties = TypeList<Ps...>;
+ using DataDrivenProperties = FilteredTypeList<Properties, IsDataDriven>;
+ using Binders = PaintPropertyBinders<DataDrivenProperties>;
+
using EvaluatedTypes = TypeList<typename Ps::EvaluatedType...>;
using UnevaluatedTypes = TypeList<typename Ps::UnevaluatedType...>;
using CascadingTypes = TypeList<typename Ps::CascadingType...>;
@@ -177,6 +215,11 @@ public:
cascading.template get<P>().set(value, klass);
}
+ template <class P>
+ void setTransition(const TransitionOptions& value, const optional<std::string>& klass) {
+ cascading.template get<P>().setTransition(value, klass);
+ }
+
void cascade(const CascadeParameters& parameters) {
unevaluated = Unevaluated {
cascading.template get<Ps>().cascade(parameters,
@@ -186,7 +229,9 @@ public:
template <class P>
auto evaluate(const PropertyEvaluationParameters& parameters) {
- return unevaluated.template get<P>().evaluate(parameters, P::defaultValue());
+ using Evaluator = typename P::EvaluatorType;
+ return unevaluated.template get<P>()
+ .evaluate(Evaluator(parameters, P::defaultValue()), parameters.now);
}
void evaluate(const PropertyEvaluationParameters& parameters) {
diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp
new file mode 100644
index 0000000000..79c7692b2f
--- /dev/null
+++ b/src/mbgl/style/paint_property_binder.hpp
@@ -0,0 +1,287 @@
+#pragma once
+
+#include <mbgl/programs/attributes.hpp>
+#include <mbgl/gl/attribute.hpp>
+#include <mbgl/gl/uniform.hpp>
+#include <mbgl/util/type_list.hpp>
+
+namespace mbgl {
+namespace style {
+
+template <class T, class A>
+class ConstantPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ ConstantPaintPropertyBinder(T constant_)
+ : constant(std::move(constant_)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature&, std::size_t) {}
+ void upload(gl::Context&) {}
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(currentValue.constantOr(constant))
+ };
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
+ return AttributeBinding();
+ }
+
+ float interpolationFactor(float) const {
+ return 0.0f;
+ }
+
+private:
+ T constant;
+};
+
+template <class T, class A>
+class SourceFunctionPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ using Attributes = gl::Attributes<Attribute>;
+ using Vertex = typename Attributes::Vertex;
+
+ SourceFunctionPaintPropertyBinder(SourceFunction<T> function_, T defaultValue_)
+ : function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ AttributeValue value = Attribute::value(function.evaluate(feature, defaultValue));
+ for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
+ vertexVector.emplace_back(Vertex { value });
+ }
+ }
+
+ void upload(gl::Context& context) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
+ }
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(*currentValue.constant())
+ };
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<Attribute>();
+ }
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
+ return AttributeBinding();
+ }
+
+ float interpolationFactor(float) const {
+ return 0.0f;
+ }
+
+private:
+ SourceFunction<T> function;
+ T defaultValue;
+ gl::VertexVector<Vertex> vertexVector;
+ optional<gl::VertexBuffer<Vertex>> vertexBuffer;
+};
+
+template <class T, class A>
+class CompositeFunctionPaintPropertyBinder {
+public:
+ using Attribute = A;
+ using AttributeValue = typename Attribute::Value;
+ using AttributeBinding = typename Attribute::Binding;
+
+ using MinAttribute = attributes::Min<Attribute>;
+ using MaxAttribute = attributes::Max<Attribute>;
+
+ using Attributes = gl::Attributes<MinAttribute, MaxAttribute>;
+ using Vertex = typename Attributes::Vertex;
+
+ CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom, T defaultValue_)
+ : function(std::move(function_)),
+ defaultValue(std::move(defaultValue_)),
+ coveringRanges(function.coveringRanges(zoom)) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature, defaultValue);
+ AttributeValue min = Attribute::value(range.min);
+ AttributeValue max = Attribute::value(range.max);
+ for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
+ vertexVector.emplace_back(Vertex { min, max });
+ }
+ }
+
+ void upload(gl::Context& context) {
+ vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
+ }
+
+ AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return typename Attribute::ConstantBinding {
+ Attribute::value(*currentValue.constant())
+ };
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<MinAttribute>();
+ }
+ }
+
+ AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ if (currentValue.isConstant()) {
+ return AttributeBinding();
+ } else {
+ return Attributes::allVariableBindings(*vertexBuffer)
+ .template get<MaxAttribute>();
+ }
+ }
+
+ float interpolationFactor(float currentZoom) const {
+ return util::interpolationFactor(1.0f, std::get<0>(coveringRanges), currentZoom);
+ }
+
+private:
+ using InnerStops = typename CompositeFunction<T>::InnerStops;
+ CompositeFunction<T> function;
+ T defaultValue;
+ std::tuple<Range<float>, Range<InnerStops>> coveringRanges;
+ gl::VertexVector<Vertex> vertexVector;
+ optional<gl::VertexBuffer<Vertex>> vertexBuffer;
+};
+
+template <class PaintProperty>
+class PaintPropertyBinder {
+public:
+ using Type = typename PaintProperty::Type;
+ using Attribute = typename PaintProperty::Attribute;
+ using PropertyValue = typename PaintProperty::EvaluatedType;
+
+ using Binder = variant<
+ ConstantPaintPropertyBinder<Type, Attribute>,
+ SourceFunctionPaintPropertyBinder<Type, Attribute>,
+ CompositeFunctionPaintPropertyBinder<Type, Attribute>>;
+
+ PaintPropertyBinder(const PropertyValue& value, float zoom)
+ : binder(value.match(
+ [&] (const Type& constant) -> Binder {
+ return ConstantPaintPropertyBinder<Type, Attribute>(constant);
+ },
+ [&] (const SourceFunction<Type>& function) {
+ return SourceFunctionPaintPropertyBinder<Type, Attribute>(function, PaintProperty::defaultValue());
+ },
+ [&] (const CompositeFunction<Type>& function) {
+ return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom, PaintProperty::defaultValue());
+ }
+ )) {
+ }
+
+ void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
+ binder.match([&] (auto& b) {
+ b.populateVertexVector(feature, length);
+ });
+ }
+
+ void upload(gl::Context& context) {
+ binder.match([&] (auto& b) {
+ b.upload(context);
+ });
+ }
+
+ using MinAttribute = attributes::Min<Attribute>;
+ using MaxAttribute = attributes::Max<Attribute>;
+ using AttributeBinding = typename Attribute::Binding;
+
+ AttributeBinding minAttributeBinding(const PropertyValue& currentValue) const {
+ return binder.match([&] (const auto& b) {
+ return b.minAttributeBinding(currentValue);
+ });
+ }
+
+ AttributeBinding maxAttributeBinding(const PropertyValue& currentValue) const {
+ return binder.match([&] (const auto& b) {
+ return b.maxAttributeBinding(currentValue);
+ });
+ }
+
+ using InterpolationUniform = attributes::InterpolationUniform<Attribute>;
+ using InterpolationUniformValue = typename InterpolationUniform::Value;
+
+ InterpolationUniformValue interpolationUniformValue(float currentZoom) const {
+ return InterpolationUniformValue {
+ binder.match([&] (const auto& b) {
+ return b.interpolationFactor(currentZoom);
+ })
+ };
+ }
+
+private:
+ Binder binder;
+};
+
+template <class Ps>
+class PaintPropertyBinders;
+
+template <class... Ps>
+class PaintPropertyBinders<TypeList<Ps...>> {
+public:
+ using Binders = IndexedTuple<TypeList<Ps...>, TypeList<PaintPropertyBinder<Ps>...>>;
+
+ template <class EvaluatedProperties>
+ PaintPropertyBinders(const EvaluatedProperties& properties, float z)
+ : binders(PaintPropertyBinder<Ps>(properties.template get<Ps>(), z)...) {
+ (void)z; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958
+ }
+
+ void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length) {
+ util::ignore({
+ (binders.template get<Ps>().populateVertexVector(feature, length), 0)...
+ });
+ }
+
+ void upload(gl::Context& context) {
+ util::ignore({
+ (binders.template get<Ps>().upload(context), 0)...
+ });
+ }
+
+ using MinAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MinAttribute...>;
+ using MaxAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MaxAttribute...>;
+
+ using Attributes = gl::ConcatenateAttributes<MinAttributes, MaxAttributes>;
+ using AttributeBindings = typename Attributes::Bindings;
+
+ template <class EvaluatedProperties>
+ AttributeBindings attributeBindings(const EvaluatedProperties& currentProperties) const {
+ const typename MinAttributes::Bindings min {
+ binders.template get<Ps>().minAttributeBinding(currentProperties.template get<Ps>())...
+ };
+ const typename MaxAttributes::Bindings max {
+ binders.template get<Ps>().maxAttributeBinding(currentProperties.template get<Ps>())...
+ };
+ return min.concat(max);
+ }
+
+ using Uniforms = gl::Uniforms<typename PaintPropertyBinder<Ps>::InterpolationUniform...>;
+ using UniformValues = typename Uniforms::Values;
+
+ UniformValues uniformValues(float currentZoom) const {
+ (void)currentZoom; // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56958
+ return UniformValues {
+ binders.template get<Ps>().interpolationUniformValue(currentZoom)...
+ };
+ }
+
+private:
+ Binders binders;
+};
+
+} // namespace style
+} // namespace mbgl
diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp
index c6c6e50dd7..926c243733 100644
--- a/src/mbgl/style/parser.cpp
+++ b/src/mbgl/style/parser.cpp
@@ -241,10 +241,14 @@ std::vector<FontStack> Parser::fontStacks() const {
result.insert({"Open Sans Regular", "Arial Unicode MS Regular"});
} else if (textFont.isConstant()) {
result.insert(textFont.asConstant());
- } else if (textFont.isFunction()) {
- for (const auto& stop : textFont.asFunction().getStops()) {
- result.insert(stop.second);
- }
+ } else if (textFont.isCameraFunction()) {
+ textFont.asCameraFunction().stops.match(
+ [&] (const auto& stops) {
+ for (const auto& stop : stops.stops) {
+ result.insert(stop.second);
+ }
+ }
+ );
}
}
}
diff --git a/src/mbgl/style/possibly_evaluated_property_value.hpp b/src/mbgl/style/possibly_evaluated_property_value.hpp
new file mode 100644
index 0000000000..8c3f1780a6
--- /dev/null
+++ b/src/mbgl/style/possibly_evaluated_property_value.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <mbgl/style/function/source_function.hpp>
+#include <mbgl/style/function/composite_function.hpp>
+#include <mbgl/util/interpolate.hpp>
+#include <mbgl/util/variant.hpp>
+
+namespace mbgl {
+
+class GeometryTileFeature;
+
+namespace style {
+
+template <class T>
+class PossiblyEvaluatedPropertyValue {
+private:
+ using Value = variant<
+ T,
+ SourceFunction<T>,
+ CompositeFunction<T>>;
+
+ Value value;
+
+public:
+ PossiblyEvaluatedPropertyValue() = default;
+ PossiblyEvaluatedPropertyValue(Value v) : value(std::move(v)) {}
+
+ bool isConstant() const {
+ return value.template is<T>();
+ }
+
+ optional<T> constant() const {
+ return value.match(
+ [&] (const T& t) { return optional<T>(t); },
+ [&] (const auto&) { return optional<T>(); });
+ }
+
+ T constantOr(const T& t) const {
+ return constant().value_or(t);
+ }
+
+ template <class... Ts>
+ auto match(Ts&&... ts) const {
+ return value.match(std::forward<Ts>(ts)...);
+ }
+};
+
+} // namespace style
+
+namespace util {
+
+template <typename T>
+struct Interpolator<style::PossiblyEvaluatedPropertyValue<T>> {
+ style::PossiblyEvaluatedPropertyValue<T> operator()(const style::PossiblyEvaluatedPropertyValue<T>& a,
+ const style::PossiblyEvaluatedPropertyValue<T>& b,
+ const double t) const {
+ if (a.isConstant() && b.isConstant()) {
+ return { interpolate(*a.constant(), *b.constant(), t) };
+ } else {
+ return { a };
+ }
+ }
+};
+
+} // namespace util
+
+} // namespace mbgl
diff --git a/src/mbgl/style/property_evaluator.hpp b/src/mbgl/style/property_evaluator.hpp
index ca4962d948..3f629ada4f 100644
--- a/src/mbgl/style/property_evaluator.hpp
+++ b/src/mbgl/style/property_evaluator.hpp
@@ -17,7 +17,7 @@ public:
T operator()(const Undefined&) const { return defaultValue; }
T operator()(const T& constant) const { return constant; }
- T operator()(const Function<T>& fn) const { return fn.evaluate(parameters.z); }
+ T operator()(const CameraFunction<T>& fn) const { return fn.evaluate(parameters.z); }
private:
const PropertyEvaluationParameters& parameters;
diff --git a/src/mbgl/style/source_impl.cpp b/src/mbgl/style/source_impl.cpp
index 624fee8ee5..003df4f6b1 100644
--- a/src/mbgl/style/source_impl.cpp
+++ b/src/mbgl/style/source_impl.cpp
@@ -139,10 +139,10 @@ void Source::Impl::updateTiles(const UpdateParameters& parameters) {
algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
idealTiles, zoomRange, tileZoom);
- if (type != SourceType::Annotations && cache.getSize() == 0) {
+ if (type != SourceType::Annotations) {
size_t conservativeCacheSize =
- std::max((float)parameters.transformState.getSize().width / util::tileSize, 1.0f) *
- std::max((float)parameters.transformState.getSize().height / util::tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().width / tileSize, 1.0f) *
+ std::max((float)parameters.transformState.getSize().height / tileSize, 1.0f) *
(parameters.transformState.getMaxZoom() - parameters.transformState.getMinZoom() + 1) *
0.5;
cache.setSize(conservativeCacheSize);
diff --git a/src/mbgl/style/source_observer.hpp b/src/mbgl/style/source_observer.hpp
index dcbcaeabaf..9be7c67960 100644
--- a/src/mbgl/style/source_observer.hpp
+++ b/src/mbgl/style/source_observer.hpp
@@ -20,7 +20,7 @@ public:
virtual void onSourceAttributionChanged(Source&, const std::string&) {}
virtual void onSourceError(Source&, std::exception_ptr) {}
- //Source description needs to be reloaded
+ // Source description needs to be reloaded
virtual void onSourceDescriptionChanged(Source&) {}
virtual void onTileChanged(Source&, const OverscaledTileID&) {}
diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp
index 3f3bc879f7..c7c3753076 100644
--- a/src/mbgl/style/sources/geojson_source_impl.cpp
+++ b/src/mbgl/style/sources/geojson_source_impl.cpp
@@ -39,7 +39,7 @@ GeoJSONSource::Impl::~Impl() = default;
void GeoJSONSource::Impl::setURL(std::string url_) {
url = std::move(url_);
- //Signal that the source description needs a reload
+ // Signal that the source description needs a reload
if (loaded || req) {
loaded = false;
req.reset();
@@ -57,7 +57,7 @@ void GeoJSONSource::Impl::setGeoJSON(const GeoJSON& geoJSON) {
_setGeoJSON(geoJSON);
}
-//Private implementation
+// Private implementation
void GeoJSONSource::Impl::_setGeoJSON(const GeoJSON& geoJSON) {
double scale = util::EXTENT / util::tileSize;
diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp
index 0b516f7b9f..b6f14ecf4b 100644
--- a/src/mbgl/style/style.cpp
+++ b/src/mbgl/style/style.cpp
@@ -134,12 +134,12 @@ void Style::setJSON(const std::string& json) {
spriteAtlas->load(parser.spriteURL, fileSource);
loaded = true;
-
+
observer->onStyleLoaded();
}
void Style::addSource(std::unique_ptr<Source> source) {
- //Guard against duplicate source ids
+ // Guard against duplicate source ids
auto it = std::find_if(sources.begin(), sources.end(), [&](const auto& existing) {
return existing->getID() == source->getID();
});
@@ -159,7 +159,7 @@ std::unique_ptr<Source> Style::removeSource(const std::string& id) {
});
if (it == sources.end()) {
- throw std::runtime_error("no such source");
+ return nullptr;
}
auto source = std::move(*it);
@@ -231,7 +231,7 @@ std::unique_ptr<Layer> Style::removeLayer(const std::string& id) {
});
if (it == layers.end())
- throw std::runtime_error("no such layer");
+ return nullptr;
auto layer = std::move(*it);
@@ -662,12 +662,17 @@ void Style::onLayerPaintPropertyChanged(Layer&) {
observer->onUpdate(Update::RecalculateStyle | Update::Classes);
}
+void Style::onLayerDataDrivenPaintPropertyChanged(Layer& layer) {
+ layer.accept(QueueSourceReloadVisitor { updateBatch });
+ observer->onUpdate(Update::RecalculateStyle | Update::Classes | Update::Layout);
+}
+
void Style::onLayerLayoutPropertyChanged(Layer& layer, const char * property) {
layer.accept(QueueSourceReloadVisitor { updateBatch });
auto update = Update::Layout;
- //Recalculate the style for certain properties
+ // Recalculate the style for certain properties
bool needsRecalculation = strcmp(property, "icon-size") == 0 || strcmp(property, "text-size") == 0;
if (needsRecalculation) {
update |= Update::RecalculateStyle;
diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp
index d46e80e8bf..4c4bcec63a 100644
--- a/src/mbgl/style/style.hpp
+++ b/src/mbgl/style/style.hpp
@@ -146,6 +146,7 @@ private:
void onLayerFilterChanged(Layer&) override;
void onLayerVisibilityChanged(Layer&) override;
void onLayerPaintPropertyChanged(Layer&) override;
+ void onLayerDataDrivenPaintPropertyChanged(Layer&) override;
void onLayerLayoutPropertyChanged(Layer&, const char *) override;
Observer nullObserver;
diff --git a/src/mbgl/style/tile_source_impl.hpp b/src/mbgl/style/tile_source_impl.hpp
index 366e0b60a2..2b17872d2b 100644
--- a/src/mbgl/style/tile_source_impl.hpp
+++ b/src/mbgl/style/tile_source_impl.hpp
@@ -33,7 +33,7 @@ public:
const variant<std::string, Tileset>& getURLOrTileset() const {
return urlOrTileset;
}
-
+
optional<std::string> getAttribution() const override;
protected:
diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp
index 2bf1448492..175a36f0fa 100644
--- a/src/mbgl/text/glyph.hpp
+++ b/src/mbgl/text/glyph.hpp
@@ -2,6 +2,8 @@
#include <mbgl/text/glyph_range.hpp>
#include <mbgl/util/rect.hpp>
+#include <mbgl/util/traits.hpp>
+#include <mbgl/util/image.hpp>
#include <cstdint>
#include <vector>
@@ -52,25 +54,28 @@ typedef std::map<uint32_t, Glyph> GlyphPositions;
class PositionedGlyph {
public:
- explicit PositionedGlyph(uint32_t glyph_, float x_, float y_)
- : glyph(glyph_), x(x_), y(y_) {}
+ explicit PositionedGlyph(uint32_t glyph_, float x_, float y_, float angle_)
+ : glyph(glyph_), x(x_), y(y_), angle(angle_) {}
uint32_t glyph = 0;
float x = 0;
float y = 0;
+ float angle = 0;
};
+enum class WritingModeType : uint8_t;
+
class Shaping {
public:
explicit Shaping() : top(0), bottom(0), left(0), right(0) {}
- explicit Shaping(float x, float y, std::u16string text_)
- : text(std::move(text_)), top(y), bottom(y), left(x), right(x) {}
+ explicit Shaping(float x, float y, WritingModeType writingMode_)
+ : top(y), bottom(y), left(x), right(x), writingMode(writingMode_) {}
std::vector<PositionedGlyph> positionedGlyphs;
- std::u16string text;
int32_t top;
int32_t bottom;
int32_t left;
int32_t right;
+ WritingModeType writingMode;
explicit operator bool() const { return !positionedGlyphs.empty(); }
};
@@ -84,10 +89,36 @@ public:
uint32_t id = 0;
// A signed distance field of the glyph with a border (see above).
- std::string bitmap;
+ AlphaImage bitmap;
// Glyph metrics
GlyphMetrics metrics;
};
+enum class WritingModeType : uint8_t {
+ None = 0,
+ Horizontal = 1 << 0,
+ Vertical = 1 << 1,
+};
+
+constexpr WritingModeType operator|(WritingModeType a, WritingModeType b) {
+ return WritingModeType(mbgl::underlying_type(a) | mbgl::underlying_type(b));
+}
+
+constexpr WritingModeType& operator|=(WritingModeType& a, WritingModeType b) {
+ return (a = a | b);
+}
+
+constexpr bool operator&(WritingModeType lhs, WritingModeType rhs) {
+ return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs);
+}
+
+constexpr WritingModeType& operator&=(WritingModeType& lhs, WritingModeType rhs) {
+ return (lhs = WritingModeType(mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs)));
+}
+
+constexpr WritingModeType operator~(WritingModeType value) {
+ return WritingModeType(~mbgl::underlying_type(value));
+}
+
} // end namespace mbgl
diff --git a/src/mbgl/text/glyph_atlas.cpp b/src/mbgl/text/glyph_atlas.cpp
index dc1fe2b1d9..1b3f7518b5 100644
--- a/src/mbgl/text/glyph_atlas.cpp
+++ b/src/mbgl/text/glyph_atlas.cpp
@@ -23,16 +23,17 @@ GlyphAtlas::GlyphAtlas(const Size size, FileSource& fileSource_)
GlyphAtlas::~GlyphAtlas() = default;
void GlyphAtlas::requestGlyphRange(const FontStack& fontStack, const GlyphRange& range) {
- std::lock_guard<std::mutex> lock(rangesMutex);
- auto& rangeSets = ranges[fontStack];
+ std::lock_guard<std::mutex> lock(mutex);
+ auto& rangeSets = entries[fontStack].ranges;
const auto& rangeSetsIt = rangeSets.find(range);
if (rangeSetsIt != rangeSets.end()) {
return;
}
- rangeSets.emplace(range,
- std::make_unique<GlyphPBF>(this, fontStack, range, observer, fileSource));
+ rangeSets.emplace(std::piecewise_construct,
+ std::forward_as_tuple(range),
+ std::forward_as_tuple(this, fontStack, range, observer, fileSource));
}
bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet& glyphRanges) {
@@ -40,8 +41,8 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
return true;
}
- std::lock_guard<std::mutex> lock(rangesMutex);
- const auto& rangeSets = ranges[fontStack];
+ std::lock_guard<std::mutex> lock(mutex);
+ const auto& rangeSets = entries[fontStack].ranges;
bool hasRanges = true;
for (const auto& range : glyphRanges) {
@@ -55,7 +56,7 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
continue;
}
- if (!rangeSetsIt->second->isParsed()) {
+ if (!rangeSetsIt->second.isParsed()) {
hasRanges = false;
}
}
@@ -64,16 +65,8 @@ bool GlyphAtlas::hasGlyphRanges(const FontStack& fontStack, const GlyphRangeSet&
}
util::exclusive<GlyphSet> GlyphAtlas::getGlyphSet(const FontStack& fontStack) {
- auto lock = std::make_unique<std::lock_guard<std::mutex>>(glyphSetsMutex);
-
- auto it = glyphSets.find(fontStack);
- if (it == glyphSets.end()) {
- it = glyphSets.emplace(fontStack, std::make_unique<GlyphSet>()).first;
- }
-
- // FIXME: We lock all GlyphSets, but what we should
- // really do is lock only the one we are returning.
- return { it->second.get(), std::move(lock) };
+ auto lock = std::make_unique<std::lock_guard<std::mutex>>(mutex);
+ return { &entries[fontStack].glyphSet, std::move(lock) };
}
void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
@@ -83,12 +76,10 @@ void GlyphAtlas::setObserver(GlyphAtlasObserver* observer_) {
void GlyphAtlas::addGlyphs(uintptr_t tileUID,
const std::u16string& text,
const FontStack& fontStack,
- const GlyphSet& glyphSet,
+ const util::exclusive<GlyphSet>& glyphSet,
GlyphPositions& face)
{
- std::lock_guard<std::mutex> lock(mtx);
-
- const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet.getSDFs();
+ const std::map<uint32_t, SDFGlyph>& sdfs = glyphSet->getSDFs();
for (char16_t chr : text)
{
@@ -107,7 +98,7 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
const FontStack& fontStack,
const SDFGlyph& glyph)
{
- std::map<uint32_t, GlyphValue>& face = index[fontStack];
+ std::map<uint32_t, GlyphValue>& face = entries[fontStack].glyphValues;
auto it = face.find(glyph.id);
// The glyph is already in this texture.
@@ -124,48 +115,26 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
return Rect<uint16_t>{ 0, 0, 0, 0 };
}
- uint16_t buffered_width = glyph.metrics.width + SDFGlyph::borderSize * 2;
- uint16_t buffered_height = glyph.metrics.height + SDFGlyph::borderSize * 2;
-
- // Guard against mismatches between the glyph bitmap size and the size mandated by
- // its metrics.
- if (size_t(buffered_width * buffered_height) != glyph.bitmap.size()) {
- return Rect<uint16_t>{ 0, 0, 0, 0 };
- }
-
// Add a 1px border around every image.
- const uint16_t padding = 1;
- uint16_t pack_width = buffered_width + 2 * padding;
- uint16_t pack_height = buffered_height + 2 * padding;
+ const uint32_t padding = 1;
+ uint16_t width = glyph.bitmap.size.width + 2 * padding;
+ uint16_t height = glyph.bitmap.size.height + 2 * padding;
// Increase to next number divisible by 4, but at least 1.
// This is so we can scale down the texture coordinates and pack them
// into 2 bytes rather than 4 bytes.
- pack_width += (4 - pack_width % 4);
- pack_height += (4 - pack_height % 4);
+ width += (4 - width % 4);
+ height += (4 - height % 4);
- Rect<uint16_t> rect = bin.allocate(pack_width, pack_height);
+ Rect<uint16_t> rect = bin.allocate(width, height);
if (rect.w == 0) {
Log::Error(Event::OpenGL, "glyph bitmap overflow");
return rect;
}
- // Verify that binpack didn't produce a rect that goes beyond the size of the image.
- // This should never happen.
- assert(rect.x + rect.w <= image.size.width);
- assert(rect.y + rect.h <= image.size.height);
-
face.emplace(glyph.id, GlyphValue { rect, tileUID });
- // Copy the bitmap
- const uint8_t* source = reinterpret_cast<const uint8_t*>(glyph.bitmap.data());
- for (uint32_t y = 0; y < buffered_height; y++) {
- uint32_t y1 = image.size.width * (rect.y + y + padding) + rect.x + padding;
- uint32_t y2 = buffered_width * y;
- for (uint32_t x = 0; x < buffered_width; x++) {
- image.data[y1 + x] = source[y2 + x];
- }
- }
+ AlphaImage::copy(glyph.bitmap, image, { 0, 0 }, { rect.x + padding, rect.y + padding }, glyph.bitmap.size);
dirty = true;
@@ -173,10 +142,10 @@ Rect<uint16_t> GlyphAtlas::addGlyph(uintptr_t tileUID,
}
void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
- std::lock_guard<std::mutex> lock(mtx);
+ std::lock_guard<std::mutex> lock(mutex);
- for (auto& faces : index) {
- std::map<uint32_t, GlyphValue>& face = faces.second;
+ for (auto& entry : entries) {
+ std::map<uint32_t, GlyphValue>& face = entry.second.glyphValues;
for (auto it = face.begin(); it != face.end(); /* we advance in the body */) {
GlyphValue& value = it->second;
value.ids.erase(tileUID);
@@ -212,8 +181,6 @@ Size GlyphAtlas::getSize() const {
}
void GlyphAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
- std::lock_guard<std::mutex> lock(mtx);
-
if (!texture) {
texture = context.createTexture(image, unit);
} else if (dirty) {
diff --git a/src/mbgl/text/glyph_atlas.hpp b/src/mbgl/text/glyph_atlas.hpp
index af14aace5b..8267630096 100644
--- a/src/mbgl/text/glyph_atlas.hpp
+++ b/src/mbgl/text/glyph_atlas.hpp
@@ -17,8 +17,6 @@
#include <unordered_set>
#include <unordered_map>
#include <mutex>
-#include <exception>
-#include <vector>
namespace mbgl {
@@ -57,7 +55,7 @@ public:
void addGlyphs(uintptr_t tileUID,
const std::u16string& text,
const FontStack&,
- const GlyphSet&,
+ const util::exclusive<GlyphSet>&,
GlyphPositions&);
void removeGlyphs(uintptr_t tileUID);
@@ -77,20 +75,9 @@ private:
const FontStack&,
const SDFGlyph&);
-
FileSource& fileSource;
std::string glyphURL;
- std::unordered_map<FontStack, std::map<GlyphRange, std::unique_ptr<GlyphPBF>>, FontStackHash> ranges;
- std::mutex rangesMutex;
-
- std::unordered_map<FontStack, std::unique_ptr<GlyphSet>, FontStackHash> glyphSets;
- std::mutex glyphSetsMutex;
-
- util::WorkQueue workQueue;
-
- GlyphAtlasObserver* observer = nullptr;
-
struct GlyphValue {
GlyphValue(Rect<uint16_t> rect_, uintptr_t id)
: rect(std::move(rect_)), ids({ id }) {}
@@ -98,10 +85,20 @@ private:
std::unordered_set<uintptr_t> ids;
};
- std::mutex mtx;
+ struct Entry {
+ std::map<GlyphRange, GlyphPBF> ranges;
+ GlyphSet glyphSet;
+ std::map<uint32_t, GlyphValue> glyphValues;
+ };
+
+ std::unordered_map<FontStack, Entry, FontStackHash> entries;
+ std::mutex mutex;
+
+ util::WorkQueue workQueue;
+ GlyphAtlasObserver* observer = nullptr;
+
BinPack<uint16_t> bin;
- std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index;
- const AlphaImage image;
+ AlphaImage image;
std::atomic<bool> dirty;
mbgl::optional<gl::Texture> texture;
};
diff --git a/src/mbgl/text/glyph_pbf.cpp b/src/mbgl/text/glyph_pbf.cpp
index cdeac57984..5c57d278db 100644
--- a/src/mbgl/text/glyph_pbf.cpp
+++ b/src/mbgl/text/glyph_pbf.cpp
@@ -25,6 +25,7 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
auto glyph_pbf = fontstack_pbf.get_message();
SDFGlyph glyph;
+ protozero::data_view glyphData;
bool hasID = false, hasWidth = false, hasHeight = false, hasLeft = false,
hasTop = false, hasAdvance = false;
@@ -36,7 +37,7 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
hasID = true;
break;
case 2: // bitmap
- glyph.bitmap = glyph_pbf.get_string();
+ glyphData = glyph_pbf.get_view();
break;
case 3: // width
glyph.metrics.width = glyph_pbf.get_uint32();
@@ -64,26 +65,35 @@ void parseGlyphPBF(GlyphSet& glyphSet, const GlyphRange& glyphRange, const std::
}
}
+ // Only treat this glyph as a correct glyph if it has all required fields. It also
+ // needs to satisfy a few metrics conditions that ensure that the glyph isn't bogus.
+ // All other glyphs are malformed. We're also discarding all glyphs that are outside
+ // the expected glyph range.
+ if (!hasID || !hasWidth || !hasHeight || !hasLeft || !hasTop || !hasAdvance ||
+ glyph.metrics.width >= 256 || glyph.metrics.height >= 256 ||
+ glyph.metrics.left < -128 || glyph.metrics.left >= 128 ||
+ glyph.metrics.top < -128 || glyph.metrics.top >= 128 ||
+ glyph.metrics.advance >= 256 ||
+ glyph.id < glyphRange.first || glyph.id > glyphRange.second) {
+ continue;
+ }
+
// If the area of width/height is non-zero, we need to adjust the expected size
// with the implicit border size, otherwise we expect there to be no bitmap at all.
- const uint32_t expectedBitmapSize =
- glyph.metrics.width && glyph.metrics.height
- ? (glyph.metrics.width + 2 * SDFGlyph::borderSize) *
- (glyph.metrics.height + 2 * SDFGlyph::borderSize)
- : 0;
-
- // Only treat this glyph as a correct glyph if it has all required fields, and if
- // the bitmap has the correct length. It also needs to satisfy a few metrics conditions
- // that ensure that the glyph isn't bogus. All other glyphs are malformed.
- // We're also discarding all glyphs that are outside the expected glyph range.
- if (hasID && hasWidth && hasHeight && hasLeft && hasTop && hasAdvance &&
- glyph.metrics.width < 256 && glyph.metrics.height < 256 &&
- glyph.metrics.left >= -128 && glyph.metrics.left < 128 &&
- glyph.metrics.top >= -128 && glyph.metrics.top < 128 &&
- glyph.metrics.advance < 256 && glyph.bitmap.size() == expectedBitmapSize &&
- glyph.id >= glyphRange.first && glyph.id <= glyphRange.second) {
- glyphSet.insert(glyph.id, std::move(glyph));
+ if (glyph.metrics.width && glyph.metrics.height) {
+ const Size size {
+ glyph.metrics.width + 2 * SDFGlyph::borderSize,
+ glyph.metrics.height + 2 * SDFGlyph::borderSize
+ };
+
+ if (size.area() != glyphData.size()) {
+ continue;
+ }
+
+ glyph.bitmap = AlphaImage(size, reinterpret_cast<const uint8_t*>(glyphData.data()), glyphData.size());
}
+
+ glyphSet.insert(glyph.id, std::move(glyph));
}
}
}
diff --git a/src/mbgl/text/glyph_set.cpp b/src/mbgl/text/glyph_set.cpp
index f9a90f9bb0..19a6e2cddd 100644
--- a/src/mbgl/text/glyph_set.cpp
+++ b/src/mbgl/text/glyph_set.cpp
@@ -42,18 +42,17 @@ const Shaping GlyphSet::getShaping(const std::u16string& logicalInput,
const float justify,
const float spacing,
const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode,
BiDi& bidi) const {
-
- // The string stored in shaping.text is used for finding duplicates, but may end up quite
- // different from the glyphs that get shown
- Shaping shaping(translate.x * 24, translate.y * 24, logicalInput);
+ Shaping shaping(translate.x * 24, translate.y * 24, writingMode);
std::vector<std::u16string> reorderedLines =
bidi.processText(logicalInput,
- determineLineBreaks(logicalInput, spacing, maxWidth));
+ determineLineBreaks(logicalInput, spacing, maxWidth, writingMode));
shapeLines(shaping, reorderedLines, spacing, lineHeight, horizontalAlign, verticalAlign,
- justify, translate);
+ justify, translate, verticalHeight, writingMode);
return shaping;
}
@@ -114,7 +113,7 @@ float GlyphSet::determineAverageLineWidth(const std::u16string& logicalInput,
int32_t targetLineCount = std::fmax(1, std::ceil(totalWidth / maxWidth));
return totalWidth / targetLineCount;
}
-
+
float calculateBadness(const float lineWidth, const float targetWidth, const float penalty, const bool isLastBreak) {
const float raggedness = std::pow(lineWidth - targetWidth, 2);
if (isLastBreak) {
@@ -130,7 +129,7 @@ float calculateBadness(const float lineWidth, const float targetWidth, const flo
}
return raggedness + std::pow(penalty, 2);
}
-
+
float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
float penalty = 0;
// Force break on newline
@@ -146,28 +145,28 @@ float calculatePenalty(char16_t codePoint, char16_t nextCodePoint) {
if (nextCodePoint == 0x29 || nextCodePoint == 0xff09) {
penalty += 50;
}
-
+
return penalty;
}
-
+
struct PotentialBreak {
PotentialBreak(const std::size_t p_index, const float p_x, const PotentialBreak* p_priorBreak, const float p_badness)
: index(p_index), x(p_x), priorBreak(p_priorBreak), badness(p_badness)
{}
-
+
const std::size_t index;
const float x;
const PotentialBreak* priorBreak;
const float badness;
};
-
+
PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, const float targetWidth, const std::list<PotentialBreak>& potentialBreaks, const float penalty, const bool isLastBreak) {
// We could skip evaluating breaks where the line length (breakX - priorBreak.x) > maxWidth
// ...but in fact we allow lines longer than maxWidth (if there's no break points)
// ...and when targetWidth and maxWidth are close, strictly enforcing maxWidth can give
// more lopsided results.
-
+
const PotentialBreak* bestPriorBreak = nullptr;
float bestBreakBadness = calculateBadness(breakX, targetWidth, penalty, isLastBreak);
for (const auto& potentialBreak : potentialBreaks) {
@@ -182,7 +181,7 @@ PotentialBreak evaluateBreak(const std::size_t breakIndex, const float breakX, c
return PotentialBreak(breakIndex, breakX, bestPriorBreak, bestBreakBadness);
}
-
+
std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
std::set<std::size_t> leastBadBreaks = { lastLineBreak.index };
const PotentialBreak* priorBreak = lastLineBreak.priorBreak;
@@ -198,17 +197,18 @@ std::set<std::size_t> leastBadBreaks(const PotentialBreak& lastLineBreak) {
// more intuitive, but we can't do that because the visual order may be changed by line breaks!
std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
- float maxWidth) const {
- if (!maxWidth) {
+ float maxWidth,
+ const WritingModeType writingMode) const {
+ if (!maxWidth || writingMode != WritingModeType::Horizontal) {
return {};
}
if (logicalInput.empty()) {
return {};
}
-
+
const float targetWidth = determineAverageLineWidth(logicalInput, spacing, maxWidth);
-
+
std::list<PotentialBreak> potentialBreaks;
float currentX = 0;
@@ -218,7 +218,7 @@ std::set<std::size_t> GlyphSet::determineLineBreaks(const std::u16string& logica
if (it != sdfs.end() && !boost::algorithm::is_any_of(u" \t\n\v\f\r")(codePoint)) {
currentX += it->second.metrics.advance + spacing;
}
-
+
// Ideographic characters, spaces, and word-breaking punctuation that often appear without
// surrounding spaces.
if ((i < logicalInput.size() - 1) &&
@@ -239,7 +239,9 @@ void GlyphSet::shapeLines(Shaping& shaping,
const float horizontalAlign,
const float verticalAlign,
const float justify,
- const Point<float>& translate) const {
+ const Point<float>& translate,
+ const float verticalHeight,
+ const WritingModeType writingMode) const {
// the y offset *should* be part of the font metadata
const int32_t yOffset = -17;
@@ -266,15 +268,21 @@ void GlyphSet::shapeLines(Shaping& shaping,
}
const SDFGlyph& glyph = it->second;
- shaping.positionedGlyphs.emplace_back(chr, x, y);
- x += glyph.metrics.advance + spacing;
+
+ if (writingMode == WritingModeType::Horizontal || !util::i18n::hasUprightVerticalOrientation(chr)) {
+ shaping.positionedGlyphs.emplace_back(chr, x, y, 0);
+ x += glyph.metrics.advance + spacing;
+ } else {
+ shaping.positionedGlyphs.emplace_back(chr, x, 0, -M_PI_2);
+ x += verticalHeight + spacing;
+ }
}
// Only justify if we placed at least one glyph
if (shaping.positionedGlyphs.size() != lineStartIndex) {
float lineLength = x - spacing; // Don't count trailing spacing
maxLineLength = util::max(lineLength, maxLineLength);
-
+
justifyLine(shaping.positionedGlyphs, sdfs, lineStartIndex,
shaping.positionedGlyphs.size() - 1, justify);
}
diff --git a/src/mbgl/text/glyph_set.hpp b/src/mbgl/text/glyph_set.hpp
index 3037cefca0..0342c82eb5 100644
--- a/src/mbgl/text/glyph_set.hpp
+++ b/src/mbgl/text/glyph_set.hpp
@@ -18,6 +18,8 @@ public:
float justify,
float spacing,
const Point<float>& translate,
+ float verticalHeight,
+ const WritingModeType,
BiDi& bidi) const;
private:
@@ -26,7 +28,8 @@ private:
float maxWidth) const;
std::set<std::size_t> determineLineBreaks(const std::u16string& logicalInput,
const float spacing,
- float maxWidth) const;
+ float maxWidth,
+ const WritingModeType) const;
void shapeLines(Shaping& shaping,
const std::vector<std::u16string>& lines,
@@ -35,7 +38,9 @@ private:
float horizontalAlign,
float verticalAlign,
float justify,
- const Point<float>& translate) const;
+ const Point<float>& translate,
+ float verticalHeight,
+ const WritingModeType) const;
std::map<uint32_t, SDFGlyph> sdfs;
};
diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp
index 1a05e6f94f..6113d1f5d4 100644
--- a/src/mbgl/text/quads.cpp
+++ b/src/mbgl/text/quads.cpp
@@ -13,7 +13,7 @@ using namespace style;
const float globalMinScale = 0.5f; // underscale by 1 zoom level
-SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
+SymbolQuad getIconQuad(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout,
const style::SymbolPlacementType placement, const Shaping& shapedText) {
@@ -62,7 +62,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
bl = {left, bottom};
}
- float angle = layout.get<IconRotate>() * util::DEG2RAD;
+ float angle = shapedIcon.angle;
if (placement == style::SymbolPlacementType::Line) {
assert(static_cast<unsigned int>(anchor.segment) < line.size());
const GeometryCoordinate &prev= line[anchor.segment];
@@ -88,9 +88,7 @@ SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
br = util::matrixMultiply(matrix, br);
}
- SymbolQuads quads;
- quads.emplace_back(tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity());
- return quads;
+ return SymbolQuad { tl, tr, bl, br, image.pos, 0, 0, anchor.point, globalMinScale, std::numeric_limits<float>::infinity(), shapedText.writingMode };
}
struct GlyphInstance {
@@ -207,10 +205,19 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
const float x2 = x1 + rect.w;
const float y2 = y1 + rect.h;
- const Point<float> otl{x1, y1};
- const Point<float> otr{x2, y1};
- const Point<float> obl{x1, y2};
- const Point<float> obr{x2, y2};
+ const Point<float> center{positionedGlyph.x, static_cast<float>(static_cast<float>(glyph.metrics.advance) / 2.0)};
+
+ Point<float> otl{x1, y1};
+ Point<float> otr{x2, y1};
+ Point<float> obl{x1, y2};
+ Point<float> obr{x2, y2};
+
+ if (positionedGlyph.angle != 0) {
+ otl = util::rotate(otl - center, positionedGlyph.angle) + center;
+ otr = util::rotate(otr - center, positionedGlyph.angle) + center;
+ obl = util::rotate(obl - center, positionedGlyph.angle) + center;
+ obr = util::rotate(obr - center, positionedGlyph.angle) + center;
+ }
for (const GlyphInstance &instance : glyphInstances) {
@@ -236,7 +243,7 @@ SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText,
const float anchorAngle = std::fmod((anchor.angle + instance.offset + 2 * M_PI), (2 * M_PI));
const float glyphAngle = std::fmod((instance.angle + instance.offset + 2 * M_PI), (2 * M_PI));
- quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale);
+ quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale, shapedText.writingMode);
}
diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp
index 75fb53aade..07a94c763b 100644
--- a/src/mbgl/text/quads.hpp
+++ b/src/mbgl/text/quads.hpp
@@ -15,7 +15,7 @@ class PositionedIcon;
struct SymbolQuad {
explicit SymbolQuad(Point<float> tl_, Point<float> tr_, Point<float> bl_, Point<float> br_,
Rect<uint16_t> tex_, float anchorAngle_, float glyphAngle_, Point<float> anchorPoint_,
- float minScale_, float maxScale_)
+ float minScale_, float maxScale_, WritingModeType writingMode_)
: tl(std::move(tl_)),
tr(std::move(tr_)),
bl(std::move(bl_)),
@@ -25,18 +25,20 @@ struct SymbolQuad {
glyphAngle(glyphAngle_),
anchorPoint(std::move(anchorPoint_)),
minScale(minScale_),
- maxScale(maxScale_) {}
+ maxScale(maxScale_),
+ writingMode(writingMode_) {}
Point<float> tl, tr, bl, br;
Rect<uint16_t> tex;
float anchorAngle, glyphAngle;
Point<float> anchorPoint;
float minScale, maxScale;
+ WritingModeType writingMode;
};
typedef std::vector<SymbolQuad> SymbolQuads;
-SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon,
+SymbolQuad getIconQuad(Anchor& anchor, const PositionedIcon& shapedIcon,
const GeometryCoordinates& line, const style::SymbolLayoutProperties::Evaluated&,
style::SymbolPlacementType placement, const Shaping& shapedText);
diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp
index 062066aaf4..e68566d419 100644
--- a/src/mbgl/text/shaping.cpp
+++ b/src/mbgl/text/shaping.cpp
@@ -1,19 +1,17 @@
#include <mbgl/text/shaping.hpp>
-#include <mbgl/style/layers/symbol_layer_properties.hpp>
+#include <mbgl/layout/symbol_feature.hpp>
namespace mbgl {
-using namespace style;
-
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const SymbolLayoutProperties::Evaluated& layout) {
- float dx = layout.get<IconOffset>()[0];
- float dy = layout.get<IconOffset>()[1];
+PositionedIcon shapeIcon(const SpriteAtlasElement& image, const std::array<float, 2>& iconOffset, const float iconRotation) {
+ float dx = iconOffset[0];
+ float dy = iconOffset[1];
float x1 = dx - image.spriteImage->getWidth() / 2.0f;
float x2 = x1 + image.spriteImage->getWidth();
float y1 = dy - image.spriteImage->getHeight() / 2.0f;
float y2 = y1 + image.spriteImage->getHeight();
- return PositionedIcon(image, y1, y2, x1, x2);
+ return PositionedIcon(image, y1, y2, x1, x2, iconRotation);
}
} // namespace mbgl
diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp
index 30375179b6..1b7b8b2733 100644
--- a/src/mbgl/text/shaping.hpp
+++ b/src/mbgl/text/shaping.hpp
@@ -3,29 +3,39 @@
#include <mbgl/text/glyph.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>
#include <mbgl/sprite/sprite_image.hpp>
-#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/util/optional.hpp>
namespace mbgl {
class SpriteAtlasElement;
+class SymbolFeature;
class PositionedIcon {
- public:
- explicit PositionedIcon() {}
- explicit PositionedIcon(const SpriteAtlasElement& _image,
- float _top, float _bottom, float _left, float _right) :
- image(_image), top(_top), bottom(_bottom), left(_left), right(_right) {}
-
- optional<SpriteAtlasElement> image;
- float top = 0;
- float bottom = 0;
- float left = 0;
- float right = 0;
-
- explicit operator bool() const { return image && (*image).pos.hasArea(); }
+public:
+ PositionedIcon() = default;
+ PositionedIcon(const SpriteAtlasElement& image_,
+ float top_,
+ float bottom_,
+ float left_,
+ float right_,
+ float angle_)
+ : image(image_),
+ top(top_),
+ bottom(bottom_),
+ left(left_),
+ right(right_),
+ angle(angle_) {}
+
+ optional<SpriteAtlasElement> image;
+ float top = 0;
+ float bottom = 0;
+ float left = 0;
+ float right = 0;
+ float angle = 0;
+
+ explicit operator bool() const { return image && (*image).pos.hasArea(); }
};
-PositionedIcon shapeIcon(const SpriteAtlasElement& image, const style::SymbolLayoutProperties::Evaluated&);
+PositionedIcon shapeIcon(const SpriteAtlasElement&, const std::array<float, 2>& iconOffset, const float iconRotation);
} // namespace mbgl
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 61437b79b1..85d8b75619 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -25,6 +25,10 @@ public:
return feature.properties;
}
+ optional<FeatureIdentifier> getID() const override {
+ return feature.id;
+ }
+
GeometryCollection getGeometries() const override {
GeometryCollection geometry = apply_visitor(ToGeometryCollection(), feature.geometry);
@@ -80,7 +84,7 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
const style::UpdateParameters& parameters)
: GeometryTile(overscaledTileID, sourceID_, parameters) {
}
-
+
void GeoJSONTile::updateData(const mapbox::geometry::feature_collection<int16_t>& features) {
setData(std::make_unique<GeoJSONTileData>(features));
}
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index 2880408736..6ddc6ea482 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -16,7 +16,7 @@ public:
const style::UpdateParameters&);
void updateData(const mapbox::geometry::feature_collection<int16_t>&);
-
+
void setNecessity(Necessity) final;
};
diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp
index 2e465a6f65..ebf27e7858 100644
--- a/src/mbgl/tile/geometry_tile_data.cpp
+++ b/src/mbgl/tile/geometry_tile_data.cpp
@@ -127,7 +127,7 @@ void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
polygon.begin() + 1 + maxHoles,
polygon.end(),
[] (const auto& a, const auto& b) {
- return signedArea(a) > signedArea(b);
+ return std::fabs(signedArea(a)) > std::fabs(signedArea(b));
});
polygon.resize(1 + maxHoles);
}
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 2a86b7feda..b1fd7a852e 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -6,6 +6,8 @@
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/group_by_layout.hpp>
+#include <mbgl/style/filter.hpp>
+#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
@@ -212,7 +214,7 @@ void GeometryTileWorker::redoLayout() {
std::unordered_map<std::string, std::unique_ptr<SymbolLayout>> symbolLayoutMap;
std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets;
auto featureIndex = std::make_unique<FeatureIndex>();
- BucketParameters parameters { id, obsolete, *featureIndex, mode };
+ BucketParameters parameters { id, mode };
std::vector<std::vector<const Layer*>> groups = groupByLayout(*layers);
for (auto& group : groups) {
@@ -240,12 +242,27 @@ void GeometryTileWorker::redoLayout() {
if (leader.is<SymbolLayer>()) {
symbolLayoutMap.emplace(leader.getID(),
- leader.as<SymbolLayer>()->impl->createLayout(parameters, *geometryLayer, layerIDs));
+ leader.as<SymbolLayer>()->impl->createLayout(parameters, group, *geometryLayer));
} else {
- std::shared_ptr<Bucket> bucket = leader.baseImpl->createBucket(parameters, *geometryLayer);
+ const Filter& filter = leader.baseImpl->filter;
+ const std::string& sourceLayerID = leader.baseImpl->sourceLayer;
+ std::shared_ptr<Bucket> bucket = leader.baseImpl->createBucket(parameters, group);
+
+ for (std::size_t i = 0; !obsolete && i < geometryLayer->featureCount(); i++) {
+ std::unique_ptr<GeometryTileFeature> feature = geometryLayer->getFeature(i);
+
+ if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); }))
+ continue;
+
+ GeometryCollection geometries = feature->getGeometries();
+ bucket->addFeature(*feature, geometries);
+ featureIndex->insert(geometries, i, sourceLayerID, leader.getID());
+ }
+
if (!bucket->hasData()) {
continue;
}
+
for (const auto& layer : group) {
buckets.emplace(layer->getID(), bucket);
}
@@ -324,8 +341,8 @@ void GeometryTileWorker::attemptPlacement() {
}
std::shared_ptr<Bucket> bucket = symbolLayout->place(*collisionTile);
- for (const auto& layerID : symbolLayout->layerIDs) {
- buckets.emplace(layerID, bucket);
+ for (const auto& pair : symbolLayout->layerPaintProperties) {
+ buckets.emplace(pair.first, bucket);
}
}
diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp
index c7a051f841..2347f8c881 100644
--- a/src/mbgl/tile/raster_tile.cpp
+++ b/src/mbgl/tile/raster_tile.cpp
@@ -41,13 +41,13 @@ void RasterTile::setData(std::shared_ptr<const std::string> data,
void RasterTile::onParsed(std::unique_ptr<Bucket> result) {
bucket = std::move(result);
- availableData = DataAvailability::All;
+ availableData = bucket ? DataAvailability::All : DataAvailability::None;
observer->onTileChanged(*this);
}
void RasterTile::onError(std::exception_ptr err) {
bucket.reset();
- availableData = DataAvailability::All;
+ availableData = DataAvailability::None;
observer->onTileError(*this, err);
}
diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp
index 219e9a2e41..8c1fc2f673 100644
--- a/src/mbgl/tile/raster_tile_worker.cpp
+++ b/src/mbgl/tile/raster_tile_worker.cpp
@@ -1,6 +1,6 @@
#include <mbgl/tile/raster_tile_worker.hpp>
#include <mbgl/tile/raster_tile.hpp>
-#include <mbgl/renderer/raster_bucket.cpp>
+#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/util/premultiply.hpp>
diff --git a/src/mbgl/tile/tile_id_hash.hpp b/src/mbgl/tile/tile_id_hash.hpp
index 0f52d9816f..f978f20e55 100644
--- a/src/mbgl/tile/tile_id_hash.hpp
+++ b/src/mbgl/tile/tile_id_hash.hpp
@@ -14,7 +14,7 @@ template <> struct hash<mbgl::CanonicalTileID> {
return seed;
}
};
-
+
template <> struct hash<mbgl::UnwrappedTileID> {
size_t operator()(const mbgl::UnwrappedTileID &id) const {
std::size_t seed = 0;
@@ -23,7 +23,7 @@ template <> struct hash<mbgl::UnwrappedTileID> {
return seed;
}
};
-
+
template <> struct hash<mbgl::OverscaledTileID> {
size_t operator()(const mbgl::OverscaledTileID &id) const {
std::size_t seed = 0;
@@ -33,5 +33,5 @@ template <> struct hash<mbgl::OverscaledTileID> {
}
};
-} // namespace std
+} // namespace std
diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp
index a195885415..68f48e81fd 100644
--- a/src/mbgl/tile/vector_tile.cpp
+++ b/src/mbgl/tile/vector_tile.cpp
@@ -15,9 +15,23 @@ class VectorTileLayer;
using packed_iter_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>;
+struct VectorTileLayerData {
+ VectorTileLayerData(std::shared_ptr<const std::string>);
+
+ // Hold a reference to the underlying pbf data that backs the lazily-built
+ // components of the owning VectorTileLayer and VectorTileFeature objects
+ std::shared_ptr<const std::string> data;
+
+ uint32_t version = 1;
+ uint32_t extent = 4096;
+ std::unordered_map<std::string, uint32_t> keysMap;
+ std::vector<std::reference_wrapper<const std::string>> keys;
+ std::vector<Value> values;
+};
+
class VectorTileFeature : public GeometryTileFeature {
public:
- VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&);
+ VectorTileFeature(protozero::pbf_reader, std::shared_ptr<VectorTileLayerData> layerData);
FeatureType getType() const override { return type; }
optional<Value> getValue(const std::string&) const override;
@@ -26,16 +40,16 @@ public:
GeometryCollection getGeometries() const override;
private:
- const VectorTileLayer& layer;
+ std::shared_ptr<VectorTileLayerData> layerData;
optional<FeatureIdentifier> id;
FeatureType type = FeatureType::Unknown;
packed_iter_type tags_iter;
packed_iter_type geometry_iter;
};
-
+
class VectorTileLayer : public GeometryTileLayer {
public:
- VectorTileLayer(protozero::pbf_reader);
+ VectorTileLayer(protozero::pbf_reader, std::shared_ptr<const std::string>);
std::size_t featureCount() const override { return features.size(); }
std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const override;
@@ -46,12 +60,8 @@ private:
friend class VectorTileFeature;
std::string name;
- uint32_t version = 1;
- uint32_t extent = 4096;
- std::unordered_map<std::string, uint32_t> keysMap;
- std::vector<std::reference_wrapper<const std::string>> keys;
- std::vector<Value> values;
std::vector<protozero::pbf_reader> features;
+ std::shared_ptr<VectorTileLayerData> data;
};
class VectorTileData : public GeometryTileData {
@@ -117,8 +127,8 @@ Value parseValue(protozero::pbf_reader data) {
return false;
}
-VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const VectorTileLayer& layer_)
- : layer(layer_) {
+VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, std::shared_ptr<VectorTileLayerData> layerData_)
+ : layerData(std::move(layerData_)) {
while (feature_pbf.next()) {
switch (feature_pbf.tag()) {
case 1: // id
@@ -141,8 +151,8 @@ VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const Ve
}
optional<Value> VectorTileFeature::getValue(const std::string& key) const {
- auto keyIter = layer.keysMap.find(key);
- if (keyIter == layer.keysMap.end()) {
+ auto keyIter = layerData->keysMap.find(key);
+ if (keyIter == layerData->keysMap.end()) {
return optional<Value>();
}
@@ -151,7 +161,7 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
while (start_itr != end_itr) {
uint32_t tag_key = static_cast<uint32_t>(*start_itr++);
- if (layer.keysMap.size() <= tag_key) {
+ if (layerData->keysMap.size() <= tag_key) {
throw std::runtime_error("feature referenced out of range key");
}
@@ -160,12 +170,12 @@ optional<Value> VectorTileFeature::getValue(const std::string& key) const {
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);;
- if (layer.values.size() <= tag_val) {
+ if (layerData->values.size() <= tag_val) {
throw std::runtime_error("feature referenced out of range value");
}
if (tag_key == keyIter->second) {
- return layer.values[tag_val];
+ return layerData->values[tag_val];
}
}
@@ -182,7 +192,7 @@ std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const {
throw std::runtime_error("uneven number of feature tag ids");
}
uint32_t tag_val = static_cast<uint32_t>(*start_itr++);
- properties[layer.keys.at(tag_key)] = layer.values.at(tag_val);
+ properties[layerData->keys.at(tag_key)] = layerData->values.at(tag_val);
}
return properties;
}
@@ -196,7 +206,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
uint32_t length = 0;
int32_t x = 0;
int32_t y = 0;
- const float scale = float(util::EXTENT) / layer.extent;
+ const float scale = float(util::EXTENT) / layerData->extent;
GeometryCollection lines;
@@ -234,7 +244,7 @@ GeometryCollection VectorTileFeature::getGeometries() const {
}
}
- if (layer.version >= 2 || type != FeatureType::Polygon) {
+ if (layerData->version >= 2 || type != FeatureType::Polygon) {
return lines;
}
@@ -250,7 +260,7 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
parsed = true;
protozero::pbf_reader tile_pbf(*data);
while (tile_pbf.next(3)) {
- VectorTileLayer layer(tile_pbf.get_message());
+ VectorTileLayer layer(tile_pbf.get_message(), data);
layers.emplace(layer.name, std::move(layer));
}
}
@@ -262,7 +272,13 @@ const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const
return nullptr;
}
-VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
+VectorTileLayerData::VectorTileLayerData(std::shared_ptr<const std::string> pbfData) :
+ data(std::move(pbfData))
+{}
+
+VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf, std::shared_ptr<const std::string> pbfData)
+ : data(std::make_shared<VectorTileLayerData>(std::move(pbfData)))
+{
while (layer_pbf.next()) {
switch (layer_pbf.tag()) {
case 1: // name
@@ -273,18 +289,18 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
break;
case 3: // keys
{
- auto iter = keysMap.emplace(layer_pbf.get_string(), keysMap.size());
- keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
+ auto iter = data->keysMap.emplace(layer_pbf.get_string(), data->keysMap.size());
+ data->keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first));
}
break;
case 4: // values
- values.emplace_back(parseValue(layer_pbf.get_message()));
+ data->values.emplace_back(parseValue(layer_pbf.get_message()));
break;
case 5: // extent
- extent = layer_pbf.get_uint32();
+ data->extent = layer_pbf.get_uint32();
break;
case 15: // version
- version = layer_pbf.get_uint32();
+ data->version = layer_pbf.get_uint32();
break;
default:
layer_pbf.skip();
@@ -294,7 +310,7 @@ VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) {
}
std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const {
- return std::make_unique<VectorTileFeature>(features.at(i), *this);
+ return std::make_unique<VectorTileFeature>(features.at(i), data);
}
std::string VectorTileLayer::getName() const {
diff --git a/src/mbgl/util/chrono.cpp b/src/mbgl/util/chrono.cpp
index f338f524b9..5c8fd3c0ff 100644
--- a/src/mbgl/util/chrono.cpp
+++ b/src/mbgl/util/chrono.cpp
@@ -33,7 +33,7 @@ std::string iso8601(Timestamp timestamp) {
Timestamp parseTimestamp(const char* timestamp) {
return std::chrono::time_point_cast<Seconds>(std::chrono::system_clock::from_time_t(parse_date(timestamp)));
}
-
+
Timestamp parseTimestamp(const int32_t timestamp) {
return std::chrono::time_point_cast<Seconds>(std::chrono::system_clock::from_time_t(timestamp));
}
diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp
index e337d4c8ab..40711232ff 100644
--- a/src/mbgl/util/http_header.cpp
+++ b/src/mbgl/util/http_header.cpp
@@ -28,7 +28,7 @@ CacheControl CacheControl::parse(const std::string& value) {
optional<Timestamp> CacheControl::toTimePoint() const {
return maxAge ? util::now() + Seconds(*maxAge) : optional<Timestamp>{};
}
-
+
optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
const optional<std::string>& xRateLimitReset) {
if (retryAfter) {
@@ -45,7 +45,7 @@ optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
return {};
}
}
-
+
return {};
}
diff --git a/src/mbgl/util/http_header.hpp b/src/mbgl/util/http_header.hpp
index fa76cb724e..23da2c9ea4 100644
--- a/src/mbgl/util/http_header.hpp
+++ b/src/mbgl/util/http_header.hpp
@@ -17,7 +17,7 @@ public:
optional<Timestamp> toTimePoint() const;
};
-
+
optional<Timestamp> parseRetryHeaders(const optional<std::string>& retryAfter,
const optional<std::string>& xRateLimitReset);
diff --git a/src/mbgl/util/http_timeout.cpp b/src/mbgl/util/http_timeout.cpp
index ded0128ac9..ca9a93498f 100644
--- a/src/mbgl/util/http_timeout.cpp
+++ b/src/mbgl/util/http_timeout.cpp
@@ -17,7 +17,7 @@ Duration errorRetryTimeout(Response::Error::Reason failedRequestReason, uint32_t
if (retryAfter) {
return *retryAfter - util::now();
} else {
- //Default
+ // Default
return Seconds(util::DEFAULT_RATE_LIMIT_TIMEOUT);
}
} else {
@@ -34,7 +34,7 @@ Duration expirationTimeout(optional<Timestamp> expires, uint32_t expiredRequests
} else {
return Duration::max();
}
-}
+}
} // namespace http
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 33ce5e22de..8e56877a64 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -1,5 +1,7 @@
#include "i18n.hpp"
+#include <map>
+
namespace {
/** Defines a function that returns true if a codepoint is in a named block.
@@ -8,7 +10,7 @@ namespace {
@param last The last codepoint in the block, inclusive.
*/
#define DEFINE_IS_IN_UNICODE_BLOCK(name, first, last) \
- inline bool isIn##name(uint16_t codepoint) { \
+ inline bool isIn##name(char16_t codepoint) { \
return codepoint >= first && codepoint <= last; \
}
@@ -16,7 +18,7 @@ namespace {
// Keep it synchronized with <http://www.unicode.org/Public/UCD/latest/ucd/Blocks.txt>.
// DEFINE_IS_IN_UNICODE_BLOCK(BasicLatin, 0x0000, 0x007F)
-// DEFINE_IS_IN_UNICODE_BLOCK(Latin1Supplement, 0x0080, 0x00FF)
+DEFINE_IS_IN_UNICODE_BLOCK(Latin1Supplement, 0x0080, 0x00FF)
// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedA, 0x0100, 0x017F)
// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedB, 0x0180, 0x024F)
// DEFINE_IS_IN_UNICODE_BLOCK(IPAExtensions, 0x0250, 0x02AF)
@@ -50,11 +52,11 @@ namespace {
// DEFINE_IS_IN_UNICODE_BLOCK(Tibetan, 0x0F00, 0x0FFF)
// DEFINE_IS_IN_UNICODE_BLOCK(Myanmar, 0x1000, 0x109F)
// DEFINE_IS_IN_UNICODE_BLOCK(Georgian, 0x10A0, 0x10FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamo, 0x1100, 0x11FF)
+DEFINE_IS_IN_UNICODE_BLOCK(HangulJamo, 0x1100, 0x11FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Ethiopic, 0x1200, 0x137F)
// DEFINE_IS_IN_UNICODE_BLOCK(EthiopicSupplement, 0x1380, 0x139F)
// DEFINE_IS_IN_UNICODE_BLOCK(Cherokee, 0x13A0, 0x13FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F)
+DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F)
// DEFINE_IS_IN_UNICODE_BLOCK(Ogham, 0x1680, 0x169F)
// DEFINE_IS_IN_UNICODE_BLOCK(Runic, 0x16A0, 0x16FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Tagalog, 0x1700, 0x171F)
@@ -63,7 +65,7 @@ namespace {
// DEFINE_IS_IN_UNICODE_BLOCK(Tagbanwa, 0x1760, 0x177F)
// 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(UnifiedCanadianAboriginalSyllabicsExtended, 0x18B0, 0x18FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Limbu, 0x1900, 0x194F)
// DEFINE_IS_IN_UNICODE_BLOCK(TaiLe, 0x1950, 0x197F)
// DEFINE_IS_IN_UNICODE_BLOCK(NewTaiLue, 0x1980, 0x19DF)
@@ -84,22 +86,22 @@ namespace {
// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksSupplement, 0x1DC0, 0x1DFF)
// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedAdditional, 0x1E00, 0x1EFF)
// DEFINE_IS_IN_UNICODE_BLOCK(GreekExtended, 0x1F00, 0x1FFF)
-// DEFINE_IS_IN_UNICODE_BLOCK(GeneralPunctuation, 0x2000, 0x206F)
+DEFINE_IS_IN_UNICODE_BLOCK(GeneralPunctuation, 0x2000, 0x206F)
// DEFINE_IS_IN_UNICODE_BLOCK(SuperscriptsandSubscripts, 0x2070, 0x209F)
// DEFINE_IS_IN_UNICODE_BLOCK(CurrencySymbols, 0x20A0, 0x20CF)
// DEFINE_IS_IN_UNICODE_BLOCK(CombiningDiacriticalMarksforSymbols, 0x20D0, 0x20FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(LetterlikeSymbols, 0x2100, 0x214F)
-// DEFINE_IS_IN_UNICODE_BLOCK(NumberForms, 0x2150, 0x218F)
+DEFINE_IS_IN_UNICODE_BLOCK(LetterlikeSymbols, 0x2100, 0x214F)
+DEFINE_IS_IN_UNICODE_BLOCK(NumberForms, 0x2150, 0x218F)
// DEFINE_IS_IN_UNICODE_BLOCK(Arrows, 0x2190, 0x21FF)
// DEFINE_IS_IN_UNICODE_BLOCK(MathematicalOperators, 0x2200, 0x22FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousTechnical, 0x2300, 0x23FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(ControlPictures, 0x2400, 0x243F)
-// DEFINE_IS_IN_UNICODE_BLOCK(OpticalCharacterRecognition, 0x2440, 0x245F)
-// DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumerics, 0x2460, 0x24FF)
+DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousTechnical, 0x2300, 0x23FF)
+DEFINE_IS_IN_UNICODE_BLOCK(ControlPictures, 0x2400, 0x243F)
+DEFINE_IS_IN_UNICODE_BLOCK(OpticalCharacterRecognition, 0x2440, 0x245F)
+DEFINE_IS_IN_UNICODE_BLOCK(EnclosedAlphanumerics, 0x2460, 0x24FF)
// DEFINE_IS_IN_UNICODE_BLOCK(BoxDrawing, 0x2500, 0x257F)
// DEFINE_IS_IN_UNICODE_BLOCK(BlockElements, 0x2580, 0x259F)
-// DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapes, 0x25A0, 0x25FF)
-// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbols, 0x2600, 0x26FF)
+DEFINE_IS_IN_UNICODE_BLOCK(GeometricShapes, 0x25A0, 0x25FF)
+DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousSymbols, 0x2600, 0x26FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Dingbats, 0x2700, 0x27BF)
// DEFINE_IS_IN_UNICODE_BLOCK(MiscellaneousMathematicalSymbolsA, 0x27C0, 0x27EF)
// DEFINE_IS_IN_UNICODE_BLOCK(SupplementalArrowsA, 0x27F0, 0x27FF)
@@ -123,15 +125,15 @@ DEFINE_IS_IN_UNICODE_BLOCK(CJKSymbolsandPunctuation, 0x3000, 0x303F)
DEFINE_IS_IN_UNICODE_BLOCK(Hiragana, 0x3040, 0x309F)
DEFINE_IS_IN_UNICODE_BLOCK(Katakana, 0x30A0, 0x30FF)
DEFINE_IS_IN_UNICODE_BLOCK(Bopomofo, 0x3100, 0x312F)
-// DEFINE_IS_IN_UNICODE_BLOCK(HangulCompatibilityJamo, 0x3130, 0x318F)
-// DEFINE_IS_IN_UNICODE_BLOCK(Kanbun, 0x3190, 0x319F)
+DEFINE_IS_IN_UNICODE_BLOCK(HangulCompatibilityJamo, 0x3130, 0x318F)
+DEFINE_IS_IN_UNICODE_BLOCK(Kanbun, 0x3190, 0x319F)
DEFINE_IS_IN_UNICODE_BLOCK(BopomofoExtended, 0x31A0, 0x31BF)
DEFINE_IS_IN_UNICODE_BLOCK(CJKStrokes, 0x31C0, 0x31EF)
DEFINE_IS_IN_UNICODE_BLOCK(KatakanaPhoneticExtensions, 0x31F0, 0x31FF)
DEFINE_IS_IN_UNICODE_BLOCK(EnclosedCJKLettersandMonths, 0x3200, 0x32FF)
DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibility, 0x3300, 0x33FF)
DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographsExtensionA, 0x3400, 0x4DBF)
-// DEFINE_IS_IN_UNICODE_BLOCK(YijingHexagramSymbols, 0x4DC0, 0x4DFF)
+DEFINE_IS_IN_UNICODE_BLOCK(YijingHexagramSymbols, 0x4DC0, 0x4DFF)
DEFINE_IS_IN_UNICODE_BLOCK(CJKUnifiedIdeographs, 0x4E00, 0x9FFF)
DEFINE_IS_IN_UNICODE_BLOCK(YiSyllables, 0xA000, 0xA48F)
DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
@@ -148,7 +150,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
// DEFINE_IS_IN_UNICODE_BLOCK(DevanagariExtended, 0xA8E0, 0xA8FF)
// DEFINE_IS_IN_UNICODE_BLOCK(KayahLi, 0xA900, 0xA92F)
// DEFINE_IS_IN_UNICODE_BLOCK(Rejang, 0xA930, 0xA95F)
-// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedA, 0xA960, 0xA97F)
+DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedA, 0xA960, 0xA97F)
// DEFINE_IS_IN_UNICODE_BLOCK(Javanese, 0xA980, 0xA9DF)
// DEFINE_IS_IN_UNICODE_BLOCK(MyanmarExtendedB, 0xA9E0, 0xA9FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Cham, 0xAA00, 0xAA5F)
@@ -159,12 +161,12 @@ DEFINE_IS_IN_UNICODE_BLOCK(YiRadicals, 0xA490, 0xA4CF)
// DEFINE_IS_IN_UNICODE_BLOCK(LatinExtendedE, 0xAB30, 0xAB6F)
// DEFINE_IS_IN_UNICODE_BLOCK(CherokeeSupplement, 0xAB70, 0xABBF)
// DEFINE_IS_IN_UNICODE_BLOCK(MeeteiMayek, 0xABC0, 0xABFF)
-// DEFINE_IS_IN_UNICODE_BLOCK(HangulSyllables, 0xAC00, 0xD7AF)
-// DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedB, 0xD7B0, 0xD7FF)
+DEFINE_IS_IN_UNICODE_BLOCK(HangulSyllables, 0xAC00, 0xD7AF)
+DEFINE_IS_IN_UNICODE_BLOCK(HangulJamoExtendedB, 0xD7B0, 0xD7FF)
// DEFINE_IS_IN_UNICODE_BLOCK(HighSurrogates, 0xD800, 0xDB7F)
// DEFINE_IS_IN_UNICODE_BLOCK(HighPrivateUseSurrogates, 0xDB80, 0xDBFF)
// DEFINE_IS_IN_UNICODE_BLOCK(LowSurrogates, 0xDC00, 0xDFFF)
-// DEFINE_IS_IN_UNICODE_BLOCK(PrivateUseArea, 0xE000, 0xF8FF)
+DEFINE_IS_IN_UNICODE_BLOCK(PrivateUseArea, 0xE000, 0xF8FF)
DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographs, 0xF900, 0xFAFF)
// DEFINE_IS_IN_UNICODE_BLOCK(AlphabeticPresentationForms, 0xFB00, 0xFB4F)
// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsA, 0xFB50, 0xFDFF)
@@ -172,7 +174,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityIdeographs, 0xF900, 0xFAFF)
DEFINE_IS_IN_UNICODE_BLOCK(VerticalForms, 0xFE10, 0xFE1F)
// DEFINE_IS_IN_UNICODE_BLOCK(CombiningHalfMarks, 0xFE20, 0xFE2F)
DEFINE_IS_IN_UNICODE_BLOCK(CJKCompatibilityForms, 0xFE30, 0xFE4F)
-// DEFINE_IS_IN_UNICODE_BLOCK(SmallFormVariants, 0xFE50, 0xFE6F)
+DEFINE_IS_IN_UNICODE_BLOCK(SmallFormVariants, 0xFE50, 0xFE6F)
// DEFINE_IS_IN_UNICODE_BLOCK(ArabicPresentationFormsB, 0xFE70, 0xFEFF)
DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(Specials, 0xFFF0, 0xFFFF)
@@ -288,13 +290,33 @@ DEFINE_IS_IN_UNICODE_BLOCK(HalfwidthandFullwidthForms, 0xFF00, 0xFFEF)
// DEFINE_IS_IN_UNICODE_BLOCK(VariationSelectorsSupplement, 0xE0100, 0xE01EF)
// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaA, 0xF0000, 0xFFFFF)
// DEFINE_IS_IN_UNICODE_BLOCK(SupplementaryPrivateUseAreaB, 0x100000, 0x10FFFF)
+
+const std::map<char16_t, char16_t> verticalPunctuation = {
+ { u'!', u'︕' }, { u'#', u'#' }, { u'$', u'$' }, { u'%', u'%' }, { u'&', u'&' },
+ { u'(', u'︵' }, { u')', u'︶' }, { u'*', u'*' }, { u'+', u'+' }, { u',', u'︐' },
+ { u'-', u'︲' }, { u'.', u'・' }, { u'/', u'/' }, { u':', u'︓' }, { u';', u'︔' },
+ { u'<', u'︿' }, { u'=', u'=' }, { u'>', u'﹀' }, { u'?', u'︖' }, { u'@', u'@' },
+ { u'[', u'﹇' }, { u'\\', u'\' }, { u']', u'﹈' }, { u'^', u'^' }, { u'_', u'︳' },
+ { u'`', u'`' }, { u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'~', u'~' },
+ { u'¢', u'¢' }, { u'£', u'£' }, { u'¥', u'¥' }, { u'¦', u'¦' }, { u'¬', u'¬' },
+ { u'¯', u' ̄' }, { u'–', u'︲' }, { u'—', u'︱' }, { u'‘', u'﹃' }, { u'’', u'﹄' },
+ { u'“', u'﹁' }, { u'”', u'﹂' }, { u'…', u'︙' }, { u'‧', u'・' }, { u'₩', u'₩' },
+ { u'、', u'︑' }, { u'。', u'︒' }, { u'〈', u'︿' }, { u'〉', u'﹀' }, { u'《', u'︽' },
+ { u'》', u'︾' }, { u'「', u'﹁' }, { u'」', u'﹂' }, { u'『', u'﹃' }, { u'』', u'﹄' },
+ { u'【', u'︻' }, { u'】', u'︼' }, { u'〔', u'︹' }, { u'〕', u'︺' }, { u'〖', u'︗' },
+ { u'〗', u'︘' }, { u'!', u'︕' }, { u'(', u'︵' }, { u')', u'︶' }, { u',', u'︐' },
+ { u'-', u'︲' }, { u'.', u'・' }, { u':', u'︓' }, { u';', u'︔' }, { u'<', u'︿' },
+ { u'>', u'﹀' }, { u'?', u'︖' }, { u'[', u'﹇' }, { u']', u'﹈' }, { u'_', u'︳' },
+ { u'{', u'︷' }, { u'|', u'―' }, { u'}', u'︸' }, { u'⦅', u'︵' }, { u'⦆', u'︶' },
+ { u'。', u'︒' }, { u'「', u'﹁' }, { u'」', u'﹂' },
+};
}
namespace mbgl {
namespace util {
namespace i18n {
-bool allowsWordBreaking(uint16_t chr) {
+bool allowsWordBreaking(char16_t chr) {
return (chr == 0x0a /* newline */
|| chr == 0x20 /* space */
|| chr == 0x26 /* ampersand */
@@ -311,7 +333,7 @@ bool allowsWordBreaking(uint16_t chr) {
}
bool allowsIdeographicBreaking(const std::u16string& string) {
- for (uint16_t chr : string) {
+ for (char16_t chr : string) {
if (!allowsIdeographicBreaking(chr)) {
return false;
}
@@ -319,7 +341,7 @@ bool allowsIdeographicBreaking(const std::u16string& string) {
return true;
}
-bool allowsIdeographicBreaking(uint16_t chr) {
+bool allowsIdeographicBreaking(char16_t chr) {
// Allow U+2027 "Interpunct" for hyphenation of Chinese words
if (chr == 0x2027)
return true;
@@ -352,6 +374,188 @@ bool allowsIdeographicBreaking(uint16_t chr) {
// || isInCJKCompatibilityIdeographsSupplement(chr));
}
+bool allowsVerticalWritingMode(const std::u16string& string) {
+ for (char32_t chr : string) {
+ if (hasUprightVerticalOrientation(chr)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// The following logic comes from
+// <http://www.unicode.org/Public/vertical/revision-16/VerticalOrientation-16.txt>.
+// The data file denotes with “U” or “Tu” any codepoint that may be drawn
+// upright in vertical text but does not distinguish between upright and
+// “neutral” characters.
+
+bool hasUprightVerticalOrientation(char16_t chr) {
+ if (chr == u'˪' || chr == u'˫')
+ return true;
+
+ // Return early for characters outside all ranges whose characters remain
+ // upright in vertical writing mode.
+ if (chr < 0x1100)
+ return false;
+
+ if (isInBopomofo(chr) || isInBopomofoExtended(chr))
+ return true;
+ if (isInCJKCompatibilityForms(chr)) {
+ if (!(chr >= u'﹉' && chr <= u'﹏'))
+ return true;
+ }
+ if (isInCJKCompatibility(chr) || isInCJKCompatibilityIdeographs(chr) ||
+ isInCJKRadicalsSupplement(chr) || isInCJKStrokes(chr))
+ return true;
+ if (isInCJKSymbolsandPunctuation(chr)) {
+ if (!(chr >= u'〈' && chr <= u'】') && !(chr >= u'〔' && chr <= u'〟') && chr != u'〰')
+ return true;
+ }
+ if (isInCJKUnifiedIdeographs(chr) || isInCJKUnifiedIdeographsExtensionA(chr) ||
+ isInEnclosedCJKLettersandMonths(chr) || isInHangulCompatibilityJamo(chr) ||
+ isInHangulJamo(chr) || isInHangulJamoExtendedA(chr) || isInHangulJamoExtendedB(chr) ||
+ isInHangulSyllables(chr) || isInHiragana(chr) ||
+ isInIdeographicDescriptionCharacters(chr) || isInKanbun(chr) || isInKangxiRadicals(chr))
+ return true;
+ if (isInKatakana(chr)) {
+ if (chr != u'ー')
+ return true;
+ }
+ if (isInKatakanaPhoneticExtensions(chr))
+ return true;
+ if (isInHalfwidthandFullwidthForms(chr)) {
+ if (chr != u'(' && chr != u')' && chr != u'-' && !(chr >= u':' && chr <= u'>') &&
+ chr != u'[' && chr != u']' && chr != u'_' && !(chr >= u'{' && chr <= 0xFFDF) &&
+ chr != u' ̄' && !(chr >= u'│' && chr <= 0xFFEF))
+ return true;
+ }
+ if (isInSmallFormVariants(chr)) {
+ if (!(chr >= u'﹘' && chr <= u'﹞') && !(chr >= u'﹣' && chr <= u'﹦'))
+ return true;
+ }
+ if (isInUnifiedCanadianAboriginalSyllabics(chr) ||
+ isInUnifiedCanadianAboriginalSyllabicsExtended(chr) || isInVerticalForms(chr) ||
+ isInYijingHexagramSymbols(chr) || isInYiSyllables(chr) || isInYiRadicals(chr))
+ return true;
+
+ // https://github.com/mapbox/mapbox-gl/issues/29
+
+ // if (isInMeroiticHieroglyphs(chr)) return true;
+ // if (isInSiddham(chr)) return true;
+ // if (isInEgyptianHieroglyphs(chr)) return true;
+ // if (isInAnatolianHieroglyphs(chr)) return true;
+ // if (isInIdeographicSymbolsandPunctuation(chr)) return true;
+ // if (isInTangut(chr)) return true;
+ // if (isInTangutComponents(chr)) return true;
+ // if (isInKanaSupplement(chr)) return true;
+ // if (isInByzantineMusicalSymbols(chr)) return true;
+ // if (isInMusicalSymbols(chr)) return true;
+ // if (isInTaiXuanJingSymbols(chr)) return true;
+ // if (isInCountingRodNumerals(chr)) return true;
+ // if (isInSuttonSignWriting(chr)) return true;
+ // if (isInMahjongTiles(chr)) return true;
+ // if (isInDominoTiles(chr)) return true;
+ // if (isInPlayingCards(chr)) return true;
+ // if (isInEnclosedAlphanumericSupplement(chr)) return true;
+ // if (isInEnclosedIdeographicSupplement(chr)) return true;
+ // if (isInMiscellaneousSymbolsandPictographs(chr)) return true;
+ // if (isInEmoticons(chr)) return true;
+ // if (isInOrnamentalDingbats(chr)) return true;
+ // if (isInTransportandMapSymbols(chr)) return true;
+ // if (isInAlchemicalSymbols(chr)) return true;
+ // if (isInGeometricShapesExtended(chr)) return true;
+ // if (isInSupplementalSymbolsandPictographs(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionB(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionC(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionD(chr)) return true;
+ // if (isInCJKUnifiedIdeographsExtensionE(chr)) return true;
+ // if (isInCJKCompatibilityIdeographsSupplement(chr)) return true;
+
+ return false;
+}
+
+bool hasNeutralVerticalOrientation(char16_t chr) {
+ if (isInLatin1Supplement(chr)) {
+ if (chr == u'§' || chr == u'©' || chr == u'®' || chr == u'±' || chr == u'¼' ||
+ chr == u'½' || chr == u'¾' || chr == u'×' || chr == u'÷') {
+ return true;
+ }
+ }
+ if (isInGeneralPunctuation(chr)) {
+ if (chr == u'‖' || chr == u'†' || chr == u'‡' || chr == u'‰' || chr == u'‱' ||
+ chr == u'※' || chr == u'‼' || chr == u'⁂' || chr == u'⁇' || chr == u'⁈' ||
+ chr == u'⁉' || chr == u'⁑') {
+ return true;
+ }
+ }
+ if (isInLetterlikeSymbols(chr) || isInNumberForms(chr)) {
+ return true;
+ }
+ if (isInMiscellaneousTechnical(chr)) {
+ if ((chr >= u'⌀' && chr <= u'⌇') || (chr >= u'⌌' && chr <= u'⌟') ||
+ (chr >= u'⌤' && chr <= u'⌨') || chr == u'⌫' || (chr >= u'⍽' && chr <= u'⎚') ||
+ (chr >= u'⎾' && chr <= u'⏍') || chr == u'⏏' || (chr >= u'⏑' && chr <= u'⏛') ||
+ (chr >= u'⏢' && chr <= 0x23FF)) {
+ return true;
+ }
+ }
+ if (isInControlPictures(chr) || isInOpticalCharacterRecognition(chr) ||
+ isInEnclosedAlphanumerics(chr) || isInGeometricShapes(chr)) {
+ return true;
+ }
+ if (isInMiscellaneousSymbols(chr)) {
+ if ((chr >= u'⬒' && chr <= u'⬯') ||
+ (chr >= u'⭐' && chr <= 0x2B59 /* heavy circled saltire */) ||
+ (chr >= 0x2BB8 /* upwards white arrow from bar with horizontal bar */ &&
+ chr <= 0x2BEB)) {
+ return true;
+ }
+ }
+ if (isInCJKSymbolsandPunctuation(chr) || isInKatakana(chr) || isInPrivateUseArea(chr) ||
+ isInCJKCompatibilityForms(chr) || isInSmallFormVariants(chr) ||
+ isInHalfwidthandFullwidthForms(chr)) {
+ return true;
+ }
+ if (chr == u'∞' || chr == u'∴' || chr == u'∵' ||
+ (chr >= 0x2700 /* black safety scissors */ && chr <= u'❧') ||
+ (chr >= u'❶' && chr <= u'➓') || chr == 0xFFFC /* object replacement character */ ||
+ chr == 0xFFFD /* replacement character */) {
+ return true;
+ }
+ return false;
+}
+
+bool hasRotatedVerticalOrientation(char16_t chr) {
+ return !(hasUprightVerticalOrientation(chr) || hasNeutralVerticalOrientation(chr));
+}
+
+std::u16string verticalizePunctuation(const std::u16string& input) {
+ std::u16string output;
+
+ for (size_t i = 0; i < input.size(); i++) {
+ char16_t nextCharCode = i < input.size() ? input[i + 1] : 0;
+ char16_t prevCharCode = i ? input[i - 1] : 0;
+
+ bool canReplacePunctuation =
+ ((!nextCharCode || !hasRotatedVerticalOrientation(nextCharCode) ||
+ verticalPunctuation.count(input[i + 1])) &&
+ (!prevCharCode || !hasRotatedVerticalOrientation(prevCharCode) ||
+ verticalPunctuation.count(input[i - 1])));
+
+ if (char16_t repl = canReplacePunctuation ? verticalizePunctuation(input[i]) : 0) {
+ output += repl;
+ } else {
+ output += input[i];
+ }
+ }
+
+ return output;
+}
+
+char16_t verticalizePunctuation(char16_t chr) {
+ return verticalPunctuation.count(chr) ? verticalPunctuation.at(chr) : 0;
+}
+
} // namespace i18n
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
index f1d3f53f72..186212f50d 100644
--- a/src/mbgl/util/i18n.hpp
+++ b/src/mbgl/util/i18n.hpp
@@ -8,7 +8,7 @@ namespace i18n {
/** Returns whether a line break can be inserted after the character indicated
by the given Unicode codepoint due to word breaking. */
-bool allowsWordBreaking(uint16_t chr);
+bool allowsWordBreaking(char16_t chr);
/** Returns whether a line break can be inserted after any character in the
given string. If false, line breaking should occur on word boundaries
@@ -17,7 +17,53 @@ bool allowsIdeographicBreaking(const std::u16string& string);
/** Returns whether a line break can be inserted after the character indicated
by the given Unicode codepoint due to ideographic breaking. */
-bool allowsIdeographicBreaking(uint16_t chr);
+bool allowsIdeographicBreaking(char16_t chr);
+
+/** Returns whether any substring of the given string can be drawn as vertical
+ text with upright glyphs. */
+bool allowsVerticalWritingMode(const std::u16string& string);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ upright orientation.
+
+ A character has upright orientation if it is drawn upright (unrotated)
+ whether the line is oriented horizontally or vertically, even if both
+ adjacent characters can be rotated. For example, a Chinese character is
+ always drawn upright. An uprightly oriented character causes an adjacent
+ “neutral” character to be drawn upright as well. */
+bool hasUprightVerticalOrientation(char16_t chr);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ neutral orientation.
+
+ A character has neutral orientation if it may be drawn rotated or unrotated
+ when the line is oriented vertically, depending on the orientation of the
+ adjacent characters. For example, along a verticlly oriented line, the
+ vulgar fraction ½ is drawn upright among Chinese characters but rotated
+ among Latin letters. A neutrally oriented character does not influence
+ whether an adjacent character is drawn upright or rotated.
+ */
+bool hasNeutralVerticalOrientation(char16_t chr);
+
+/** Returns true if the given Unicode codepoint identifies a character with
+ rotated orientation.
+
+ A character has rotated orientation if it is drawn rotated when the line is
+ oriented vertically, even if both adjacent characters are upright. For
+ example, a Latin letter is drawn rotated along a vertical line. A rotated
+ character causes an adjacent “neutral” character to be drawn rotated as
+ well.
+ */
+bool hasRotatedVerticalOrientation(char16_t chr);
+
+/** Returns a copy of the given string with punctuation characters replaced with
+ their vertical forms wherever applicable. */
+std::u16string verticalizePunctuation(const std::u16string& input);
+
+/** Returns the form of the given character appropriate for vertical text.
+
+ @return The character’s specialized vertical form; 0 if not applicable. */
+char16_t verticalizePunctuation(char16_t chr);
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/ignore.hpp b/src/mbgl/util/ignore.hpp
index 955b1de2fa..577bcf4d91 100644
--- a/src/mbgl/util/ignore.hpp
+++ b/src/mbgl/util/ignore.hpp
@@ -19,5 +19,8 @@ template <class... Ts> void ignore(Ts&&...) {}
//
template <class T> void ignore(const std::initializer_list<T>&) {}
+// Handle the zero-argument case.
+inline void ignore(const std::initializer_list<int>&) {}
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/indexed_tuple.hpp b/src/mbgl/util/indexed_tuple.hpp
index 110e7dce12..a414639530 100644
--- a/src/mbgl/util/indexed_tuple.hpp
+++ b/src/mbgl/util/indexed_tuple.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <mbgl/util/type_list.hpp>
+
#include <type_traits>
#include <tuple>
@@ -14,8 +16,6 @@ struct TypeIndex<T, T, Ts...> : std::integral_constant<std::size_t, 0> {};
template <class T, class U, class... Ts>
struct TypeIndex<T, U, Ts...> : std::integral_constant<std::size_t, 1 + TypeIndex<T, Ts...>::value> {};
-template <class...> class TypeList {};
-
template <class...> class IndexedTuple;
// A tuple of Ts, where individual members can be accessed via `t.get<I>()` for I ∈ Is.
@@ -42,6 +42,15 @@ public:
const auto& get() const {
return std::get<Index<I>>(*this);
}
+
+ template <class... Js, class... Us>
+ IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>>
+ concat(const IndexedTuple<TypeList<Js...>, TypeList<Us...>>& other) const {
+ return IndexedTuple<TypeList<Is..., Js...>, TypeList<Ts..., Us...>> {
+ get<Is>()...,
+ other.template get<Js>()...
+ };
+ }
};
} // namespace mbgl
diff --git a/src/mbgl/util/interpolate.cpp b/src/mbgl/util/interpolate.cpp
new file mode 100644
index 0000000000..306a5c6630
--- /dev/null
+++ b/src/mbgl/util/interpolate.cpp
@@ -0,0 +1,19 @@
+#include <mbgl/util/interpolate.hpp>
+
+#include <cmath>
+
+namespace mbgl {
+namespace util {
+
+float interpolationFactor(float base, Range<float> range, float z) {
+ const float zoomDiff = range.max - range.min;
+ const float zoomProgress = z - range.min;
+ if (base == 1.0f) {
+ return zoomProgress / zoomDiff;
+ } else {
+ return (std::pow(base, zoomProgress) - 1) / (std::pow(base, zoomDiff) - 1);
+ }
+}
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/interpolate.hpp b/src/mbgl/util/interpolate.hpp
index ef066377da..d463ffc056 100644
--- a/src/mbgl/util/interpolate.hpp
+++ b/src/mbgl/util/interpolate.hpp
@@ -1,15 +1,19 @@
#pragma once
+#include <mbgl/util/color.hpp>
+#include <mbgl/util/range.hpp>
+
#include <array>
#include <vector>
#include <string>
#include <type_traits>
#include <utility>
-#include <mbgl/util/color.hpp>
namespace mbgl {
namespace util {
+float interpolationFactor(float base, Range<float> range, float z);
+
template <class T, class Enabled = void>
struct Interpolator;
@@ -78,5 +82,8 @@ template <class T>
struct Interpolator<std::vector<T>>
: Uninterpolated {};
+template <class T>
+constexpr bool Interpolatable = !std::is_base_of<Uninterpolated, Interpolator<T>>::value;
+
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/thread.hpp b/src/mbgl/util/thread.hpp
index b03c7f3e7c..184c6a8a12 100644
--- a/src/mbgl/util/thread.hpp
+++ b/src/mbgl/util/thread.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <cassert>
#include <future>
#include <thread>
#include <atomic>
@@ -9,6 +10,7 @@
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/platform.hpp>
+#include <mbgl/util/util.hpp>
namespace mbgl {
namespace util {
@@ -47,6 +49,8 @@ public:
// Invoke object->fn(args...) asynchronously, but wait for the result.
template <typename Fn, class... Args>
auto invokeSync(Fn fn, Args&&... args) {
+ assert(!paused);
+
using R = std::result_of_t<Fn(Object, Args&&...)>;
std::packaged_task<R ()> task(std::bind(fn, object, args...));
std::future<R> future = task.get_future();
@@ -54,7 +58,39 @@ public:
return future.get();
}
+ void pause() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(!paused);
+
+ paused = std::make_unique<std::promise<void>>();
+ resumed = std::make_unique<std::promise<void>>();
+
+ auto pausing = paused->get_future();
+
+ loop->invoke([this] {
+ auto resuming = resumed->get_future();
+ paused->set_value();
+ resuming.get();
+ });
+
+ pausing.get();
+ }
+
+ void resume() {
+ MBGL_VERIFY_THREAD(tid);
+
+ assert(paused);
+
+ resumed->set_value();
+
+ resumed.reset();
+ paused.reset();
+ }
+
private:
+ MBGL_STORE_THREAD(tid);
+
Thread(const Thread&) = delete;
Thread(Thread&&) = delete;
Thread& operator=(const Thread&) = delete;
@@ -73,6 +109,9 @@ private:
std::promise<void> running;
std::promise<void> joinable;
+ std::unique_ptr<std::promise<void>> paused;
+ std::unique_ptr<std::promise<void>> resumed;
+
std::thread thread;
Object* object = nullptr;
@@ -119,6 +158,12 @@ void Thread<Object>::run(P&& params, std::index_sequence<I...>) {
template <class Object>
Thread<Object>::~Thread() {
+ MBGL_VERIFY_THREAD(tid);
+
+ if (paused) {
+ resume();
+ }
+
loop->stop();
joinable.set_value();
thread.join();
diff --git a/src/mbgl/util/type_list.hpp b/src/mbgl/util/type_list.hpp
new file mode 100644
index 0000000000..4a5e95c8a4
--- /dev/null
+++ b/src/mbgl/util/type_list.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <type_traits>
+#include <tuple>
+
+namespace mbgl {
+
+template <class...>
+class TypeList {};
+
+namespace detail {
+
+template <class, class>
+struct TypeCons;
+
+template <class T, class... Ts>
+struct TypeCons<T, TypeList<Ts...>> {
+ using Type = TypeList<T, Ts...>;
+};
+
+template <class, template <class> class>
+struct TypeFilter;
+
+template <template <class> class Predicate>
+struct TypeFilter<TypeList<>, Predicate> {
+ using Type = TypeList<>;
+};
+
+template <template <class> class Predicate, class T, class... Ts>
+struct TypeFilter<TypeList<T, Ts...>, Predicate> {
+ using Tail = typename TypeFilter<TypeList<Ts...>, Predicate>::Type;
+ using Type = std::conditional_t<Predicate<T>::value, typename TypeCons<T, Tail>::Type, Tail>;
+};
+
+} // namespace detail
+
+template <class TypeList, template <class> class Predicate>
+using FilteredTypeList = typename detail::TypeFilter<TypeList, Predicate>::Type;
+
+} // namespace mbgl
diff --git a/src/mbgl/util/url.cpp b/src/mbgl/util/url.cpp
index 0a7d096ec0..3f36bc676f 100644
--- a/src/mbgl/util/url.cpp
+++ b/src/mbgl/util/url.cpp
@@ -89,8 +89,10 @@ URL::URL(const std::string& str)
return { queryPos, (hashPos != std::string::npos ? hashPos : str.size()) - queryPos };
}()),
scheme([&]() -> Segment {
- auto schemeEnd = str.find(':');
- return { 0, schemeEnd == std::string::npos || schemeEnd > query.first ? 0 : schemeEnd };
+ if (str.empty() || !isAlphaCharacter(str.front())) return { 0, 0 };
+ size_t schemeEnd = 0;
+ while (schemeEnd < query.first && isSchemeCharacter(str[schemeEnd])) ++schemeEnd;
+ return { 0, str[schemeEnd] == ':' ? schemeEnd : 0 };
}()),
domain([&]() -> Segment {
auto domainPos = scheme.first + scheme.second;
diff --git a/src/mbgl/util/version.cpp b/src/mbgl/util/version.cpp
new file mode 100644
index 0000000000..fcb31f0b71
--- /dev/null
+++ b/src/mbgl/util/version.cpp
@@ -0,0 +1,9 @@
+#include <mbgl/util/version.hpp>
+
+namespace mbgl {
+namespace version {
+
+const char* revision = MBGL_VERSION_REV;
+
+} // namespace version
+} // namespace mbgl
diff --git a/src/mbgl/util/version.hpp b/src/mbgl/util/version.hpp
new file mode 100644
index 0000000000..e652016485
--- /dev/null
+++ b/src/mbgl/util/version.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+namespace mbgl {
+namespace version {
+
+extern const char* revision;
+
+} // namespace version
+} // namespace mbgl
diff --git a/src/mbgl/util/version_info.cpp b/src/mbgl/util/version_info.cpp
deleted file mode 100644
index f0fb139bca..0000000000
--- a/src/mbgl/util/version_info.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <mbgl/util/version.hpp>
-
-namespace mbgl {
-namespace version {
-
-const int major = MBGL_VERSION_MAJOR;
-const int minor = MBGL_VERSION_MINOR;
-const int patch = MBGL_VERSION_PATCH;
-const char *revision = MBGL_VERSION_REV;
-const char *string = MBGL_VERSION_STRING;
-const unsigned int number = MBGL_VERSION;
-
-} // namespace version
-} // namespace mbgl
diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp
index 72a2d62bde..6644e9c92c 100644
--- a/test/api/annotations.test.cpp
+++ b/test/api/annotations.test.cpp
@@ -27,7 +27,7 @@ public:
OffscreenView view { backend.getContext() };
StubFileSource fileSource;
ThreadPool threadPool { 4 };
- Map map { backend, view.size, 1, fileSource, threadPool, MapMode::Still };
+ Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
void checkRendering(const char * name) {
test::checkImage(std::string("test/fixtures/annotations/") + name,
@@ -45,13 +45,13 @@ TEST(Annotations, SymbolAnnotation) {
test.map.addAnnotation(SymbolAnnotation { Point<double>(0, 0), "default_marker" });
test.checkRendering("point_annotation");
- auto size = test.view.size;
- auto screenBox = ScreenBox { {}, { double(size.width), double(size.height) } };
- for (uint8_t zoom = test.map.getMinZoom(); zoom <= test.map.getMaxZoom(); ++zoom) {
- test.map.setZoom(zoom);
- test.checkRendering("point_annotation");
- EXPECT_EQ(test.map.queryPointAnnotations(screenBox).size(), 1u);
- }
+// auto size = test.view.getSize();
+// auto screenBox = ScreenBox { {}, { double(size.width), double(size.height) } };
+// for (uint8_t zoom = test.map.getMinZoom(); zoom <= test.map.getMaxZoom(); ++zoom) {
+// test.map.setZoom(zoom);
+// test.checkRendering("point_annotation");
+// EXPECT_EQ(test.map.queryPointAnnotations(screenBox).size(), 1u);
+// }
}
TEST(Annotations, LineAnnotation) {
@@ -351,7 +351,7 @@ TEST(Annotations, QueryRenderedFeatures) {
TEST(Annotations, QueryFractionalZoomLevels) {
AnnotationTest test;
- auto viewSize = test.view.size;
+ auto viewSize = test.view.getSize();
auto box = ScreenBox { {}, { double(viewSize.width), double(viewSize.height) } };
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
@@ -383,7 +383,7 @@ TEST(Annotations, QueryFractionalZoomLevels) {
TEST(Annotations, VisibleFeatures) {
AnnotationTest test;
- auto viewSize = test.view.size;
+ auto viewSize = test.view.getSize();
auto box = ScreenBox { {}, { double(viewSize.width), double(viewSize.height) } };
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
diff --git a/test/api/api_misuse.test.cpp b/test/api/api_misuse.test.cpp
index 34272f5366..1a61872f79 100644
--- a/test/api/api_misuse.test.cpp
+++ b/test/api/api_misuse.test.cpp
@@ -27,7 +27,7 @@ TEST(API, RenderWithoutCallback) {
ThreadPool threadPool(4);
std::unique_ptr<Map> map =
- std::make_unique<Map>(backend, view.size, 1, fileSource, threadPool, MapMode::Still);
+ std::make_unique<Map>(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
map->renderStill(view, nullptr);
// Force Map thread to join.
@@ -51,7 +51,7 @@ TEST(API, RenderWithoutStyle) {
StubFileSource fileSource;
ThreadPool threadPool(4);
- Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still);
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
std::exception_ptr error;
map.renderStill(view, [&](std::exception_ptr error_) {
diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp
index 73b4e94af5..dd56197463 100644
--- a/test/api/custom_layer.test.cpp
+++ b/test/api/custom_layer.test.cpp
@@ -97,7 +97,7 @@ TEST(CustomLayer, Basic) {
ThreadPool threadPool(4);
- Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still);
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
map.setLatLngZoom({ 37.8, -122.5 }, 10);
map.addLayer(std::make_unique<CustomLayer>(
diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp
index 86687fc818..4d2bf00f67 100644
--- a/test/api/query.test.cpp
+++ b/test/api/query.test.cpp
@@ -30,7 +30,7 @@ public:
OffscreenView view { backend.getContext() };
StubFileSource fileSource;
ThreadPool threadPool { 4 };
- Map map { backend, view.size, 1, fileSource, threadPool, MapMode::Still };
+ Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
};
} // end namespace
diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp
index a5c59913bc..c1bf7e5702 100644
--- a/test/api/render_missing.test.cpp
+++ b/test/api/render_missing.test.cpp
@@ -38,7 +38,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
Log::setObserver(std::make_unique<FixtureLogObserver>());
- Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still);
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
std::string message;
diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp
index 49b9a31b0b..800813075f 100644
--- a/test/api/repeated_render.test.cpp
+++ b/test/api/repeated_render.test.cpp
@@ -34,7 +34,7 @@ TEST(API, RepeatedRender) {
Log::setObserver(std::make_unique<FixtureLogObserver>());
- Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Still);
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
{
map.setStyleJSON(style);
diff --git a/test/fixtures/annotations/result-spriteatlas.png b/test/fixtures/annotations/result-spriteatlas.png
deleted file mode 100644
index e886e060fe..0000000000
--- a/test/fixtures/annotations/result-spriteatlas.png
+++ /dev/null
Binary files differ
diff --git a/test/fixtures/map/no_vao/expected.png b/test/fixtures/map/no_vao/expected.png
new file mode 100644
index 0000000000..d5b7c42762
--- /dev/null
+++ b/test/fixtures/map/no_vao/expected.png
Binary files differ
diff --git a/test/fixtures/sprite_atlas/basic/expected.png b/test/fixtures/sprite_atlas/basic/expected.png
new file mode 100644
index 0000000000..cd13d16df6
--- /dev/null
+++ b/test/fixtures/sprite_atlas/basic/expected.png
Binary files differ
diff --git a/test/fixtures/annotations/result-spriteatlassize.png b/test/fixtures/sprite_atlas/size/expected.png
index d9ae7dab47..d9ae7dab47 100644
--- a/test/fixtures/annotations/result-spriteatlassize.png
+++ b/test/fixtures/sprite_atlas/size/expected.png
Binary files differ
diff --git a/test/fixtures/annotations/result-spriteatlas-updated.png b/test/fixtures/sprite_atlas/updates_after/expected.png
index 3c850c0a25..3c850c0a25 100644
--- a/test/fixtures/annotations/result-spriteatlas-updated.png
+++ b/test/fixtures/sprite_atlas/updates_after/expected.png
Binary files differ
diff --git a/test/fixtures/annotations/result-spriteatlas-empty.png b/test/fixtures/sprite_atlas/updates_before/expected.png
index effcd38f1e..effcd38f1e 100644
--- a/test/fixtures/annotations/result-spriteatlas-empty.png
+++ b/test/fixtures/sprite_atlas/updates_before/expected.png
Binary files differ
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index 03cdc63a91..feda234af2 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -4,37 +4,34 @@
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
-
+#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/map/mode.hpp>
-TEST(Buckets, CircleBucket) {
- mbgl::MapMode mapMode = mbgl::MapMode::Still;
+using namespace mbgl;
- mbgl::CircleBucket bucket { mapMode };
+TEST(Buckets, CircleBucket) {
+ CircleBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
ASSERT_FALSE(bucket.hasData());
}
TEST(Buckets, FillBucket) {
- mbgl::FillBucket bucket;
+ FillBucket bucket { { {0, 0, 0}, MapMode::Still }, {} };
ASSERT_FALSE(bucket.hasData());
}
TEST(Buckets, LineBucket) {
- uint32_t overscaling = 0;
-
- mbgl::LineBucket bucket { overscaling };
+ LineBucket bucket { { {0, 0, 0}, MapMode::Still }, {}, {} };
ASSERT_FALSE(bucket.hasData());
}
TEST(Buckets, SymbolBucket) {
- mbgl::MapMode mapMode = mbgl::MapMode::Still;
- mbgl::style::SymbolLayoutProperties::Evaluated properties;
+ style::SymbolLayoutProperties::Evaluated layout;
bool sdfIcons = false;
bool iconsNeedLinear = false;
- mbgl::SymbolBucket bucket { mapMode, properties, sdfIcons, iconsNeedLinear };
+ SymbolBucket bucket { layout, {}, 0, sdfIcons, iconsNeedLinear };
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
diff --git a/test/gl/object.test.cpp b/test/gl/object.test.cpp
index f1da93f1da..85ae457081 100644
--- a/test/gl/object.test.cpp
+++ b/test/gl/object.test.cpp
@@ -1,5 +1,6 @@
#include <mbgl/test/util.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/offscreen_view.hpp>
@@ -62,6 +63,7 @@ TEST(GLObject, Value) {
TEST(GLObject, Store) {
HeadlessBackend backend { test::sharedDisplay() };
OffscreenView view(backend.getContext());
+ BackendScope scope { backend };
gl::Context context;
EXPECT_TRUE(context.empty());
@@ -77,6 +79,4 @@ TEST(GLObject, Store) {
context.reset();
EXPECT_TRUE(context.empty());
-
- backend.deactivate();
}
diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp
index 8eedeb3c01..618c2e6a74 100644
--- a/test/map/map.test.cpp
+++ b/test/map/map.test.cpp
@@ -4,12 +4,15 @@
#include <mbgl/test/fixture_log_observer.hpp>
#include <mbgl/map/map.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/offscreen_view.hpp>
+#include <mbgl/gl/context.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/storage/network_status.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/storage/online_file_source.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/io.hpp>
#include <mbgl/util/run_loop.hpp>
@@ -31,7 +34,7 @@ struct MapTest {
TEST(Map, LatLngBehavior) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
@@ -65,7 +68,7 @@ TEST(Map, Offline) {
fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf"));
NetworkStatus::Set(NetworkStatus::Status::Offline);
- Map map(test.backend, test.view.size, 1, fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
map.setStyleURL(prefix + "style.json");
test::checkImage("test/fixtures/map/offline",
@@ -89,7 +92,7 @@ TEST(Map, SetStyleInvalidJSON) {
});
{
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool,
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool,
MapMode::Still);
map.setStyleJSON("invalid");
}
@@ -121,7 +124,7 @@ TEST(Map, SetStyleInvalidURL) {
}
});
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleURL("mapbox://bar");
test.runLoop.run();
@@ -130,7 +133,7 @@ TEST(Map, SetStyleInvalidURL) {
TEST(Map, DoubleStyleLoad) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON("");
map.setStyleJSON("");
}
@@ -141,7 +144,7 @@ TEST(Map, StyleFresh) {
MapTest test;
FakeFileSource fileSource;
- Map map(test.backend, test.view.size, 1, fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
map.setStyleURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
@@ -161,7 +164,7 @@ TEST(Map, StyleExpired) {
MapTest test;
FakeFileSource fileSource;
- Map map(test.backend, test.view.size, 1, fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
map.setStyleURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
@@ -188,7 +191,7 @@ TEST(Map, StyleExpiredWithAnnotations) {
MapTest test;
FakeFileSource fileSource;
- Map map(test.backend, test.view.size, 1, fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
map.setStyleURL("mapbox://styles/test");
EXPECT_EQ(1u, fileSource.requests.size());
@@ -212,7 +215,7 @@ TEST(Map, StyleEarlyMutation) {
MapTest test;
FakeFileSource fileSource;
- Map map(test.backend, test.view.size, 1, fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
map.setStyleURL("mapbox://styles/test");
map.addLayer(std::make_unique<style::BackgroundLayer>("bg"));
@@ -226,7 +229,7 @@ TEST(Map, StyleEarlyMutation) {
TEST(Map, StyleLoadedSignal) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
// The map should emit a signal on style loaded
bool emitted = false;
@@ -237,17 +240,64 @@ TEST(Map, StyleLoadedSignal) {
});
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
EXPECT_TRUE(emitted);
-
+
// But not when the style couldn't be parsed
emitted = false;
map.setStyleJSON("invalid");
EXPECT_FALSE(emitted);
}
+// Test for https://github.com/mapbox/mapbox-gl-native/issues/7902
+TEST(Map, TEST_REQUIRES_SERVER(StyleNetworkErrorRetry)) {
+ MapTest test;
+ OnlineFileSource fileSource;
+
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
+ map.setStyleURL("http://127.0.0.1:3000/style-fail-once-500");
+
+ test.backend.setMapChangeCallback([&](MapChange change) {
+ if (change == mbgl::MapChangeDidFinishLoadingStyle) {
+ test.runLoop.stop();
+ }
+ });
+
+ test.runLoop.run();
+}
+
+TEST(Map, TEST_REQUIRES_SERVER(StyleNotFound)) {
+ MapTest test;
+ OnlineFileSource fileSource;
+
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
+ map.setStyleURL("http://127.0.0.1:3000/style-fail-once-404");
+
+ using namespace std::chrono_literals;
+ util::Timer timer;
+
+ // Not found errors should not trigger a retry like other errors.
+ test.backend.setMapChangeCallback([&](MapChange change) {
+ if (change == mbgl::MapChangeDidFinishLoadingStyle) {
+ FAIL() << "Should not retry on not found!";
+ }
+
+ if (change == mbgl::MapChangeDidFailLoadingMap) {
+ timer.start(Milliseconds(1100), 0s, [&] {
+ test.runLoop.stop();
+ });
+ }
+ });
+
+ test.runLoop.run();
+
+ // Should also not retry if the response has cache headers.
+ map.setStyleURL("http://127.0.0.1:3000/style-fail-once-404-cache");
+ test.runLoop.run();
+}
+
TEST(Map, AddLayer) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
auto layer = std::make_unique<BackgroundLayer>("background");
@@ -257,10 +307,28 @@ TEST(Map, AddLayer) {
test::checkImage("test/fixtures/map/add_layer", test::render(map, test.view));
}
+TEST(Map, WithoutVAOExtension) {
+ MapTest test;
+
+ test.backend.getContext().disableVAOExtension = true;
+
+#ifdef MBGL_ASSET_ZIP
+ // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/`
+ DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip");
+#else
+ DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
+#endif
+
+ Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
+ map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
+
+ test::checkImage("test/fixtures/map/no_vao", test::render(map, test.view), 0.002);
+}
+
TEST(Map, RemoveLayer) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
auto layer = std::make_unique<BackgroundLayer>("background");
@@ -285,7 +353,7 @@ TEST(Map, DisabledSources) {
return {};
};
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setZoom(1);
// This stylesheet has two raster layers, one that starts at zoom 1, the other at zoom 0.
@@ -335,7 +403,7 @@ TEST(Map, DisabledSources) {
TEST(Map, Classes) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
EXPECT_FALSE(map.getTransitionOptions().duration);
@@ -369,7 +437,7 @@ TEST(Map, Classes) {
TEST(Map, AddImage) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
auto decoded1 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
auto decoded2 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
auto image1 = std::make_unique<SpriteImage>(std::move(decoded1), 1.0);
@@ -386,7 +454,7 @@ TEST(Map, AddImage) {
TEST(Map, RemoveImage) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
auto image = std::make_unique<SpriteImage>(std::move(decoded), 1.0);
@@ -399,7 +467,7 @@ TEST(Map, RemoveImage) {
TEST(Map, GetImage) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
auto image = std::make_unique<SpriteImage>(std::move(decoded), 1.0);
@@ -411,7 +479,7 @@ TEST(Map, GetImage) {
TEST(Map, DontLoadUnneededTiles) {
MapTest test;
- Map map(test.backend, test.view.size, 1, test.fileSource, test.threadPool, MapMode::Still);
+ Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
map.setStyleJSON(R"STYLE({
"sources": {
"a": { "type": "vector", "tiles": [ "a/{z}/{x}/{y}" ] }
@@ -484,7 +552,7 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) {
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets");
#endif
- Map map(backend, view.size, 1, fileSource, threadPool, MapMode::Continuous);
+ Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Continuous);
using namespace std::chrono_literals;
@@ -507,6 +575,7 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) {
});
}
+ BackendScope scope(backend);
map.render(view);
}};
diff --git a/test/map/transform.test.cpp b/test/map/transform.test.cpp
index d5b98ac109..9125b6ef1d 100644
--- a/test/map/transform.test.cpp
+++ b/test/map/transform.test.cpp
@@ -343,12 +343,12 @@ TEST(Transform, Padding) {
ASSERT_DOUBLE_EQ(10, trueCenter.latitude);
ASSERT_DOUBLE_EQ(-100, trueCenter.longitude);
ASSERT_DOUBLE_EQ(10, transform.getZoom());
-
+
const LatLng manualShiftedCenter = transform.getState().screenCoordinateToLatLng({
1000.0 / 2.0,
1000.0 / 4.0,
});
-
+
EdgeInsets padding;
padding.top = 0;
@@ -359,7 +359,7 @@ TEST(Transform, Padding) {
padding.top = 1000.0 / 2.0;
ASSERT_TRUE(bool(padding));
-
+
const LatLng shiftedCenter = transform.getLatLng(padding);
ASSERT_NE(trueCenter.latitude, shiftedCenter.latitude);
ASSERT_NEAR(trueCenter.longitude, shiftedCenter.longitude, 1e-9);
diff --git a/test/math/wrap.test.cpp b/test/math/wrap.test.cpp
index 9ec1c6ef0c..5610257a5c 100644
--- a/test/math/wrap.test.cpp
+++ b/test/math/wrap.test.cpp
@@ -23,4 +23,4 @@ TEST(Math, WrapMaxValue) {
TEST(Math, WrapMinValue) {
ASSERT_DOUBLE_EQ(0.0, util::wrap(0.0, 0.0, 12.0));
-} \ No newline at end of file
+}
diff --git a/test/sprite/sprite_atlas.test.cpp b/test/sprite/sprite_atlas.test.cpp
index c9576013d4..2c425a95d2 100644
--- a/test/sprite/sprite_atlas.test.cpp
+++ b/test/sprite/sprite_atlas.test.cpp
@@ -15,14 +15,6 @@
using namespace mbgl;
-namespace {
-
-auto readImage(const std::string& name) {
- return decodeImage(util::read_file(name));
-}
-
-} // namespace
-
TEST(SpriteAtlas, Basic) {
FixtureLog log;
@@ -36,7 +28,7 @@ TEST(SpriteAtlas, Basic) {
EXPECT_EQ(63u, atlas.getSize().width);
EXPECT_EQ(112u, atlas.getSize().height);
- auto metro = *atlas.getImage("metro", SpritePatternMode::Single);
+ auto metro = *atlas.getIcon("metro");
EXPECT_EQ(0, metro.pos.x);
EXPECT_EQ(0, metro.pos.y);
EXPECT_EQ(20, metro.pos.w);
@@ -50,7 +42,7 @@ TEST(SpriteAtlas, Basic) {
EXPECT_EQ(63u, atlas.getAtlasImage().size.width);
EXPECT_EQ(112u, atlas.getAtlasImage().size.height);
- auto pos = *atlas.getPosition("metro", SpritePatternMode::Single);
+ auto pos = *atlas.getIcon("metro");
EXPECT_DOUBLE_EQ(18, pos.size[0]);
EXPECT_DOUBLE_EQ(18, pos.size[1]);
EXPECT_DOUBLE_EQ(1.0f / 63, pos.tl[0]);
@@ -58,7 +50,7 @@ TEST(SpriteAtlas, Basic) {
EXPECT_DOUBLE_EQ(19.0f / 63, pos.br[0]);
EXPECT_DOUBLE_EQ(19.0f / 112, pos.br[1]);
- auto missing = atlas.getImage("doesnotexist", SpritePatternMode::Single);
+ auto missing = atlas.getIcon("doesnotexist");
EXPECT_FALSE(missing);
EXPECT_EQ(1u, log.count({
@@ -69,13 +61,13 @@ TEST(SpriteAtlas, Basic) {
}));
// Different wrapping mode produces different image.
- auto metro2 = *atlas.getImage("metro", SpritePatternMode::Repeating);
+ auto metro2 = *atlas.getPattern("metro");
EXPECT_EQ(20, metro2.pos.x);
EXPECT_EQ(0, metro2.pos.y);
EXPECT_EQ(20, metro2.pos.w);
EXPECT_EQ(20, metro2.pos.h);
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlas.png"), atlas.getAtlasImage());
+ test::checkImage("test/fixtures/sprite_atlas/basic", atlas.getAtlasImage());
}
TEST(SpriteAtlas, Size) {
@@ -89,7 +81,7 @@ TEST(SpriteAtlas, Size) {
EXPECT_EQ(63u, atlas.getSize().width);
EXPECT_EQ(112u, atlas.getSize().height);
- auto metro = *atlas.getImage("metro", SpritePatternMode::Single);
+ auto metro = *atlas.getIcon("metro");
EXPECT_EQ(0, metro.pos.x);
EXPECT_EQ(0, metro.pos.y);
EXPECT_EQ(16, metro.pos.w);
@@ -104,8 +96,7 @@ TEST(SpriteAtlas, Size) {
EXPECT_EQ(89u, atlas.getAtlasImage().size.width);
EXPECT_EQ(157u, atlas.getAtlasImage().size.height);
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlassize.png"),
- atlas.getAtlasImage());
+ test::checkImage("test/fixtures/sprite_atlas/size", atlas.getAtlasImage());
}
TEST(SpriteAtlas, Updates) {
@@ -116,7 +107,7 @@ TEST(SpriteAtlas, Updates) {
EXPECT_EQ(32u, atlas.getSize().height);
atlas.setSprite("one", std::make_shared<SpriteImage>(PremultipliedImage({ 16, 12 }), 1));
- auto one = *atlas.getImage("one", SpritePatternMode::Single);
+ auto one = *atlas.getIcon("one");
EXPECT_EQ(0, one.pos.x);
EXPECT_EQ(0, one.pos.y);
EXPECT_EQ(20, one.pos.w);
@@ -131,8 +122,7 @@ TEST(SpriteAtlas, Updates) {
EXPECT_EQ(32u, atlas.getAtlasImage().size.width);
EXPECT_EQ(32u, atlas.getAtlasImage().size.height);
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlas-empty.png"),
- atlas.getAtlasImage());
+ test::checkImage("test/fixtures/sprite_atlas/updates_before", atlas.getAtlasImage());
// Update sprite
PremultipliedImage image2({ 16, 12 });
@@ -143,15 +133,7 @@ TEST(SpriteAtlas, Updates) {
atlas.setSprite("one", newSprite);
ASSERT_EQ(newSprite, atlas.getSprite("one"));
- // Atlas texture hasn't changed yet.
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlas-empty.png"),
- atlas.getAtlasImage());
-
- atlas.updateDirty();
-
- // Now the atlas texture has changed.
- EXPECT_EQ(readImage("test/fixtures/annotations/result-spriteatlas-updated.png"),
- atlas.getAtlasImage());
+ test::checkImage("test/fixtures/sprite_atlas/updates_after", atlas.getAtlasImage());
}
TEST(SpriteAtlas, AddRemove) {
@@ -199,6 +181,25 @@ TEST(SpriteAtlas, AddRemove) {
atlas.setSprite("three", sprite1);
}
+TEST(SpriteAtlas, RemoveReleasesBinPackRect) {
+ FixtureLog log;
+
+ SpriteAtlas atlas({ 36, 36 }, 1);
+
+ const auto big = std::make_shared<SpriteImage>(PremultipliedImage({ 32, 32 }), 1);
+
+ atlas.setSprite("big", big);
+ EXPECT_TRUE(atlas.getIcon("big"));
+
+ atlas.removeSprite("big");
+
+ atlas.setSprite("big", big);
+ EXPECT_TRUE(atlas.getIcon("big"));
+
+ EXPECT_EQ(big, atlas.getSprite("big"));
+ EXPECT_TRUE(log.empty());
+}
+
TEST(SpriteAtlas, OtherPixelRatio) {
FixtureLog log;
diff --git a/test/src/mbgl/test/conversion_stubs.hpp b/test/src/mbgl/test/conversion_stubs.hpp
index ddffb1e3b2..e6581c5e53 100644
--- a/test/src/mbgl/test/conversion_stubs.hpp
+++ b/test/src/mbgl/test/conversion_stubs.hpp
@@ -24,7 +24,7 @@ class Value : public mbgl::variant<std::string,
};
inline bool isUndefined(const Value&) {
- //Variant is always intialized
+ // Variant is always intialized
return false;
}
diff --git a/test/src/mbgl/test/getrss.cpp b/test/src/mbgl/test/getrss.cpp
new file mode 100644
index 0000000000..9f57ad8e7b
--- /dev/null
+++ b/test/src/mbgl/test/getrss.cpp
@@ -0,0 +1,102 @@
+#include <mbgl/test/getrss.hpp>
+
+/*
+ * Adapted from
+ * http://nadeausoftware.com/articles/2012/07/c_c_tip_how_get_process_resident_set_size_physical_memory_use
+ *
+ * Author: David Robert Nadeau
+ * Site: http://NadeauSoftware.com/
+ * License: Creative Commons Attribution 3.0 Unported License
+ * http://creativecommons.org/licenses/by/3.0/deed.en_US
+ */
+
+namespace mbgl {
+namespace test {
+
+/**
+ * Returns the peak (maximum so far) resident set size (physical
+ * memory use) measured in bytes, or zero if the value cannot be
+ * determined on this OS.
+ */
+size_t getPeakRSS( )
+{
+#if defined(_WIN32)
+ /* Windows -------------------------------------------------- */
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.PeakWorkingSetSize;
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+ /* AIX and Solaris ------------------------------------------ */
+ struct psinfo psinfo;
+ int fd = -1;
+ if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
+ return (size_t)0L; /* Can't open? */
+ if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
+ {
+ close( fd );
+ return (size_t)0L; /* Can't read? */
+ }
+ close( fd );
+ return (size_t)(psinfo.pr_rssize * 1024L);
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+ /* BSD, Linux, and OSX -------------------------------------- */
+ struct rusage rusage;
+ getrusage( RUSAGE_SELF, &rusage );
+#if defined(__APPLE__) && defined(__MACH__)
+ return (size_t)rusage.ru_maxrss;
+#else
+ return (size_t)(rusage.ru_maxrss * 1024L);
+#endif
+
+#else
+ /* Unknown OS ----------------------------------------------- */
+ return (size_t)0L; /* Unsupported. */
+#endif
+}
+
+/**
+ * Returns the current resident set size (physical memory use) measured
+ * in bytes, or zero if the value cannot be determined on this OS.
+ */
+size_t getCurrentRSS( )
+{
+#if defined(_WIN32)
+ /* Windows -------------------------------------------------- */
+ PROCESS_MEMORY_COUNTERS info;
+ GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
+ return (size_t)info.WorkingSetSize;
+
+#elif defined(__APPLE__) && defined(__MACH__)
+ /* OSX ------------------------------------------------------ */
+ struct mach_task_basic_info info;
+ mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
+ if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
+ (task_info_t)&info, &infoCount ) != KERN_SUCCESS )
+ return (size_t)0L; /* Can't access? */
+ return (size_t)info.resident_size;
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+ /* Linux ---------------------------------------------------- */
+ long rss = 0L;
+ FILE* fp = NULL;
+ if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
+ return (size_t)0L; /* Can't open? */
+ if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
+ {
+ fclose( fp );
+ return (size_t)0L; /* Can't read? */
+ }
+ fclose( fp );
+ return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
+
+#else
+ /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
+ return (size_t)0L; /* Unsupported. */
+#endif
+}
+
+} // namespace test
+} // namespace mbgl
+
diff --git a/test/src/mbgl/test/getrss.hpp b/test/src/mbgl/test/getrss.hpp
new file mode 100644
index 0000000000..a4420c4b5f
--- /dev/null
+++ b/test/src/mbgl/test/getrss.hpp
@@ -0,0 +1,45 @@
+#if defined(_WIN32)
+#include <windows.h>
+#include <psapi.h>
+
+#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
+#include <unistd.h>
+#include <sys/resource.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#include <mach/mach.h>
+#include <mach/message.h> // for mach_port_t
+#include <mach/task_info.h>
+
+#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
+#include <fcntl.h>
+#include <procfs.h>
+
+#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
+#include <stdio.h>
+
+#endif
+
+#else
+#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
+#endif
+
+namespace mbgl {
+namespace test {
+
+
+/**
+ * Returns the peak (maximum so far) resident set size (physical
+ * memory use) measured in bytes, or zero if the value cannot be
+ * determined on this OS.
+ */
+size_t getPeakRSS();
+
+/**
+ * Returns the current resident set size (physical memory use) measured
+ * in bytes, or zero if the value cannot be determined on this OS.
+ */
+size_t getCurrentRSS();
+
+}
+}
diff --git a/test/src/mbgl/test/stub_geometry_tile_feature.hpp b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
new file mode 100644
index 0000000000..21d198a96b
--- /dev/null
+++ b/test/src/mbgl/test/stub_geometry_tile_feature.hpp
@@ -0,0 +1,34 @@
+#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/feature.hpp>
+
+namespace mbgl {
+
+class StubGeometryTileFeature : public GeometryTileFeature {
+public:
+ StubGeometryTileFeature(PropertyMap properties_)
+ : properties(std::move(properties_)) {
+ }
+
+ PropertyMap properties;
+ optional<FeatureIdentifier> id = {};
+ FeatureType type = FeatureType::Point;
+ GeometryCollection geometry = {};
+
+ FeatureType getType() const override {
+ return type;
+ }
+
+ optional<FeatureIdentifier> getID() const override {
+ return id;
+ }
+
+ optional<Value> getValue(const std::string& key) const override {
+ return properties.count(key) ? properties.at(key) : optional<Value>();
+ }
+
+ GeometryCollection getGeometries() const override {
+ return geometry;
+ }
+};
+
+} // namespace mbgl
diff --git a/test/src/mbgl/test/stub_layer_observer.hpp b/test/src/mbgl/test/stub_layer_observer.hpp
index 07797ce921..9acd4b077a 100644
--- a/test/src/mbgl/test/stub_layer_observer.hpp
+++ b/test/src/mbgl/test/stub_layer_observer.hpp
@@ -22,6 +22,10 @@ public:
if (layerPaintPropertyChanged) layerPaintPropertyChanged(layer);
}
+ void onLayerDataDrivenPaintPropertyChanged(Layer& layer) override {
+ if (layerDataDrivenPaintPropertyChanged) layerDataDrivenPaintPropertyChanged(layer);
+ }
+
void onLayerLayoutPropertyChanged(Layer& layer, const char * property) override {
if (layerLayoutPropertyChanged) layerLayoutPropertyChanged(layer, property);
}
@@ -29,5 +33,6 @@ public:
std::function<void (Layer&)> layerFilterChanged;
std::function<void (Layer&)> layerVisibilityChanged;
std::function<void (Layer&)> layerPaintPropertyChanged;
+ std::function<void (Layer&)> layerDataDrivenPaintPropertyChanged;
std::function<void (Layer&, const char *)> layerLayoutPropertyChanged;
};
diff --git a/test/src/mbgl/test/util.hpp b/test/src/mbgl/test/util.hpp
index 34d8969d3c..82d5c520f8 100644
--- a/test/src/mbgl/test/util.hpp
+++ b/test/src/mbgl/test/util.hpp
@@ -21,7 +21,7 @@
#define TEST_IS_SIMULATOR 0
#endif
-#if !TEST_IS_SIMULATOR
+#if !TEST_IS_SIMULATOR && !CI_BUILD
#define TEST_REQUIRES_ACCURATE_TIMING(name) name
#else
#define TEST_REQUIRES_ACCURATE_TIMING(name) DISABLED_ ## name
diff --git a/test/storage/default_file_source.test.cpp b/test/storage/default_file_source.test.cpp
index f4c23c4c7a..03f1076559 100644
--- a/test/storage/default_file_source.test.cpp
+++ b/test/storage/default_file_source.test.cpp
@@ -267,6 +267,22 @@ TEST(DefaultFileSource, OptionalExpired) {
loop.run();
}
+TEST(DefaultFileSource, GetBaseURLAndAccessTokenWhilePaused) {
+ util::RunLoop loop;
+ DefaultFileSource fs(":memory:", ".");
+
+ fs.pause();
+
+ auto baseURL = "http://url";
+ auto accessToken = "access_token";
+
+ fs.setAPIBaseURL(baseURL);
+ fs.setAccessToken(accessToken);
+
+ EXPECT_EQ(fs.getAPIBaseURL(), baseURL);
+ EXPECT_EQ(fs.getAccessToken(), accessToken);
+}
+
TEST(DefaultFileSource, OptionalNotFound) {
util::RunLoop loop;
DefaultFileSource fs(":memory:", ".");
@@ -460,3 +476,33 @@ TEST(DefaultFileSource, TEST_REQUIRES_SERVER(NoCacheRefreshModifiedModified)) {
loop.run();
}
+
+TEST(DefaultFileSource, TEST_REQUIRES_SERVER(SetResourceTransform)) {
+ util::RunLoop loop;
+ DefaultFileSource fs(":memory:", ".");
+
+ // Translates the URL "localhost://test to http://127.0.0.1:3000/test
+ fs.setResourceTransform([](Resource::Kind, std::string&& url) -> std::string {
+ if (url == "localhost://test") {
+ return "http://127.0.0.1:3000/test";
+ } else {
+ return std::move(url);
+ }
+ });
+
+ const Resource resource { Resource::Unknown, "localhost://test" };
+
+ std::unique_ptr<AsyncRequest> req;
+ req = fs.request(resource, [&](Response res) {
+ req.reset();
+ EXPECT_EQ(nullptr, res.error);
+ ASSERT_TRUE(res.data.get());
+ EXPECT_EQ("Hello World!", *res.data);
+ EXPECT_FALSE(bool(res.expires));
+ EXPECT_FALSE(bool(res.modified));
+ EXPECT_FALSE(bool(res.etag));
+ loop.stop();
+ });
+
+ loop.run();
+}
diff --git a/test/storage/local_file_source.test.cpp b/test/storage/local_file_source.test.cpp
index c2f04d7543..1b90e5bb1e 100644
--- a/test/storage/local_file_source.test.cpp
+++ b/test/storage/local_file_source.test.cpp
@@ -104,14 +104,14 @@ TEST(LocalFileSource, URLEncoding) {
TEST(LocalFileSource, URLLimit) {
util::RunLoop loop;
-
+
size_t length = PATH_MAX - toAbsoluteURL("").size();
LocalFileSource fs;
char filename[length];
memset(filename, 'x', length);
-
+
std::string url(filename, length);
-
+
std::unique_ptr<AsyncRequest> req = fs.request({ Resource::Unknown, toAbsoluteURL(url) }, [&](Response res) {
req.reset();
ASSERT_NE(nullptr, res.error);
@@ -119,6 +119,6 @@ TEST(LocalFileSource, URLLimit) {
ASSERT_FALSE(res.data.get());
loop.stop();
});
-
+
loop.run();
}
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index 2e25835d80..872310e46f 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -276,12 +276,12 @@ TEST(OfflineDatabase, CreateRegion) {
TEST(OfflineDatabase, UpdateMetadata) {
using namespace mbgl;
-
+
OfflineDatabase db(":memory:");
OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 };
OfflineRegionMetadata metadata {{ 1, 2, 3 }};
OfflineRegion region = db.createRegion(definition, metadata);
-
+
OfflineRegionMetadata newmetadata {{ 4, 5, 6 }};
db.updateMetadata(region.getID(), newmetadata);
EXPECT_EQ(db.listRegions().at(0).getMetadata(), newmetadata);
diff --git a/test/storage/online_file_source.test.cpp b/test/storage/online_file_source.test.cpp
index 966ef6239a..1a1d2d42f8 100644
--- a/test/storage/online_file_source.test.cpp
+++ b/test/storage/online_file_source.test.cpp
@@ -364,7 +364,7 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(NetworkStatusOnlineOffline)) {
TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RateLimitStandard)) {
util::RunLoop loop;
OnlineFileSource fs;
-
+
auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/rate-limit?std=true" }, [&](Response res) {
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::RateLimit, res.error->reason);
@@ -372,14 +372,14 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RateLimitStandard)) {
ASSERT_LT(util::now(), res.error->retryAfter);
loop.stop();
});
-
+
loop.run();
}
TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RateLimitMBX)) {
util::RunLoop loop;
OnlineFileSource fs;
-
+
auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/rate-limit?mbx=true" }, [&](Response res) {
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::RateLimit, res.error->reason);
@@ -387,28 +387,28 @@ TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RateLimitMBX)) {
ASSERT_LT(util::now(), res.error->retryAfter);
loop.stop();
});
-
+
loop.run();
}
TEST(OnlineFileSource, TEST_REQUIRES_SERVER(RateLimitDefault)) {
util::RunLoop loop;
OnlineFileSource fs;
-
+
auto req = fs.request({ Resource::Unknown, "http://127.0.0.1:3000/rate-limit" }, [&](Response res) {
ASSERT_NE(nullptr, res.error);
EXPECT_EQ(Response::Error::Reason::RateLimit, res.error->reason);
ASSERT_FALSE(res.error->retryAfter);
loop.stop();
});
-
+
loop.run();
}
TEST(OnlineFileSource, ChangeAPIBaseURL){
util::RunLoop loop;
OnlineFileSource fs;
-
+
EXPECT_EQ(mbgl::util::API_BASE_URL, fs.getAPIBaseURL());
const std::string customURL = "test.domain";
fs.setAPIBaseURL(customURL);
diff --git a/test/storage/server.js b/test/storage/server.js
index a7538b55f1..b54ff835ec 100755
--- a/test/storage/server.js
+++ b/test/storage/server.js
@@ -117,16 +117,47 @@ app.get('/temporary-error', function(req, res) {
});
app.get('/rate-limit', function(req, res) {
-
+
if (req.query.std) {
res.setHeader('Retry-After', 1);
} else if (req.query.mbx) {
res.setHeader('x-rate-limit-reset', Math.round(Date.now() / 1000) + 1);
}
-
+
res.status(429).end();
});
+var styleFailOnce500 = true;
+app.get('/style-fail-once-500', function (req, res) {
+ if (styleFailOnce500) {
+ res.status(500).send('Server Error!');
+ styleFailOnce500 = false;
+ } else {
+ res.status(200).send('{ "version": 8, "name": "Teste Style" }');
+ }
+});
+
+var styleFailOnce404 = true;
+app.get('/style-fail-once-404', function (req, res) {
+ if (styleFailOnce404) {
+ res.status(404).send('Not found!');
+ styleFailOnce404 = false;
+ } else {
+ res.status(200).send('{ "version": 8, "name": "Teste Style" }');
+ }
+});
+
+var styleFailOnce404Cache = true;
+app.get('/style-fail-once-404-cache', function (req, res) {
+ if (styleFailOnce404Cache) {
+ res.setHeader('Cache-Control', 'max-age=30');
+ res.status(404).send('Not found!');
+ styleFailOnce404Cache = false;
+ } else {
+ res.status(200).send('{ "version": 8, "name": "Teste Style" }');
+ }
+});
+
app.get('/delayed', function(req, res) {
setTimeout(function() {
res.status(200).send('Response');
diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp
new file mode 100644
index 0000000000..dbd7a09868
--- /dev/null
+++ b/test/storage/sqlite.test.cpp
@@ -0,0 +1,27 @@
+#include <mbgl/test/util.hpp>
+
+#include <gtest/gtest.h>
+#include <sqlite3.hpp>
+
+TEST(SQLite, Statement) {
+ using namespace mbgl;
+
+ mapbox::sqlite::Database db(":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 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);
+}
diff --git a/test/style/conversion/function.test.cpp b/test/style/conversion/function.test.cpp
index e93207ea13..5a3ec93917 100644
--- a/test/style/conversion/function.test.cpp
+++ b/test/style/conversion/function.test.cpp
@@ -13,7 +13,7 @@ using namespace mbgl::style::conversion;
auto parseFunction(const std::string& src) {
JSDocument doc;
doc.Parse<0>(src);
- return convert<Function<float>>(doc);
+ return convert<CameraFunction<float>>(doc);
}
TEST(StyleConversion, Function) {
diff --git a/test/style/conversion/geojson_options.test.cpp b/test/style/conversion/geojson_options.test.cpp
index 14a7adbba7..ddf261ea52 100644
--- a/test/style/conversion/geojson_options.test.cpp
+++ b/test/style/conversion/geojson_options.test.cpp
@@ -28,13 +28,13 @@ TEST(GeoJSONOptions, RetainsDefaults) {
Value raw(map);
GeoJSONOptions converted = *convert<GeoJSONOptions>(raw);
GeoJSONOptions defaults;
-
- //GeoJSON-VT
+
+ // GeoJSON-VT
ASSERT_EQ(converted.maxzoom, defaults.maxzoom);
ASSERT_EQ(converted.buffer, defaults.buffer);
ASSERT_EQ(converted.tolerance, defaults.tolerance);
-
- //Supercluster
+
+ // Supercluster
ASSERT_EQ(converted.cluster, defaults.cluster);
ASSERT_EQ(converted.clusterRadius, defaults.clusterRadius);
ASSERT_EQ(converted.clusterMaxZoom, defaults.clusterMaxZoom);
@@ -43,25 +43,25 @@ TEST(GeoJSONOptions, RetainsDefaults) {
TEST(GeoJSONOptions, FullConversion) {
ValueMap map {
- //GeoJSON-VT
+ // GeoJSON-VT
{"maxzoom", 1.0f},
{"buffer", 2.0f},
{"tolerance", 3.0f},
-
- //Supercluster
+
+ // Supercluster
{"cluster", true},
{"clusterRadius", 4.0f},
{"clusterMaxZoom", 5.0f}
};
Value raw(map);
GeoJSONOptions converted = *convert<GeoJSONOptions>(raw);
-
- //GeoJSON-VT
+
+ // GeoJSON-VT
ASSERT_EQ(converted.maxzoom, 1);
ASSERT_EQ(converted.buffer, 2);
ASSERT_EQ(converted.tolerance, 3);
-
- //Supercluster
+
+ // Supercluster
ASSERT_EQ(converted.cluster, true);
ASSERT_EQ(converted.clusterRadius, 4);
ASSERT_EQ(converted.clusterMaxZoom, 5);
diff --git a/test/style/conversion/layer.test.cpp b/test/style/conversion/layer.test.cpp
new file mode 100644
index 0000000000..b27c1841ee
--- /dev/null
+++ b/test/style/conversion/layer.test.cpp
@@ -0,0 +1,46 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/rapidjson_conversion.hpp>
+#include <mbgl/style/conversion/layer.hpp>
+#include <mbgl/style/layers/background_layer_impl.hpp>
+#include <mbgl/util/rapidjson.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+using namespace mbgl::style::conversion;
+using namespace std::literals::chrono_literals;
+
+auto parseLayer(const std::string& src) {
+ JSDocument doc;
+ doc.Parse<0>(src);
+ return convert<std::unique_ptr<Layer>, JSValue>(doc);
+}
+
+TEST(StyleConversion, LayerTransition) {
+ auto layer = parseLayer(R"JSON({
+ "type": "background",
+ "id": "background",
+ "paint": {
+ "background-color-transition": {
+ "duration": 400,
+ "delay": 500
+ }
+ },
+ "paint.class": {
+ "background-color-transition": {
+ "duration": 100
+ }
+ }
+ })JSON");
+
+ ASSERT_EQ(400ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ .get<BackgroundColor>().getTransition({}).duration);
+ ASSERT_EQ(500ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ .get<BackgroundColor>().getTransition({}).delay);
+
+ ASSERT_EQ(100ms, *(*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ .get<BackgroundColor>().getTransition({"class"}).duration);
+ ASSERT_FALSE(bool((*layer)->as<BackgroundLayer>()->impl->paint.cascading
+ .get<BackgroundColor>().getTransition({"class"}).delay));
+}
diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp
index be5d65d4ce..1dae20b26b 100644
--- a/test/style/conversion/stringify.test.cpp
+++ b/test/style/conversion/stringify.test.cpp
@@ -79,13 +79,45 @@ TEST(Stringify, Filter) {
ASSERT_EQ(stringify(EqualsFilter { "a", 1.0 }), "[\"==\",\"a\",1.0]");
}
-TEST(Stringify, Function) {
- ASSERT_EQ(stringify(Function<float>({{0, 1}}, 2)), "{\"base\":2.0,\"stops\":[[0.0,1.0]]}");
+TEST(Stringify, CameraFunction) {
+ ASSERT_EQ(stringify(CameraFunction<float>(ExponentialStops<float> { {{0, 1}}, 2 })),
+ "{\"type\":\"exponential\",\"base\":2.0,\"stops\":[[0.0,1.0]]}");
+ ASSERT_EQ(stringify(CameraFunction<float>(IntervalStops<float> { {{0, 1}} })),
+ "{\"type\":\"interval\",\"stops\":[[0.0,1.0]]}");
+}
+
+TEST(Stringify, SourceFunction) {
+ ASSERT_EQ(stringify(SourceFunction<float>("property", ExponentialStops<float> { {{0, 1}}, 2 })),
+ "{\"property\":\"property\",\"type\":\"exponential\",\"base\":2.0,\"stops\":[[0.0,1.0]]}");
+ ASSERT_EQ(stringify(SourceFunction<float>("property", IntervalStops<float> { {{0, 1}} })),
+ "{\"property\":\"property\",\"type\":\"interval\",\"stops\":[[0.0,1.0]]}");
+ ASSERT_EQ(stringify(SourceFunction<float>("property", CategoricalStops<float> { {{CategoricalValue(true), 1}} })),
+ "{\"property\":\"property\",\"type\":\"categorical\",\"stops\":[[true,1.0]]}");
+ ASSERT_EQ(stringify(SourceFunction<float>("property", IdentityStops<float> {})),
+ "{\"property\":\"property\",\"type\":\"identity\"}");
+ ASSERT_EQ(stringify(SourceFunction<float>("property", IdentityStops<float> {}, 0.0f)),
+ "{\"property\":\"property\",\"type\":\"identity\",\"default\":0.0}");
+}
+
+TEST(Stringify, CompositeFunction) {
+ ASSERT_EQ(stringify(CompositeFunction<float>("property",
+ CompositeExponentialStops<float> {
+ {
+ { 0, {{0, 1}} },
+ { 1, {{0, 1}} }
+ },
+ 2
+ }, 0.0f)),
+ "{\"property\":\"property\",\"type\":\"exponential\",\"base\":2.0,"
+ "\"stops\":["
+ "[{\"zoom\":0.0,\"value\":0.0},1.0],"
+ "[{\"zoom\":1.0,\"value\":0.0},1.0]],\"default\":0.0}");
}
TEST(Stringify, PropertyValue) {
ASSERT_EQ(stringify(PropertyValue<float>(1)), "1.0");
- ASSERT_EQ(stringify(PropertyValue<float>(Function<float>({{0, 1}}, 2))), "{\"base\":2.0,\"stops\":[[0.0,1.0]]}");
+ ASSERT_EQ(stringify(PropertyValue<float>(CameraFunction<float>(ExponentialStops<float> { {{0, 1}}, 2 }))),
+ "{\"type\":\"exponential\",\"base\":2.0,\"stops\":[[0.0,1.0]]}");
}
TEST(Stringify, Layout) {
diff --git a/test/style/functions.test.cpp b/test/style/function/camera_function.test.cpp
index 8553d13349..6cd53b0fa0 100644
--- a/test/style/functions.test.cpp
+++ b/test/style/function/camera_function.test.cpp
@@ -17,7 +17,7 @@ bool evaluate(PropertyValue<bool> value, float zoom) {
return value.evaluate(PropertyEvaluator<bool>(PropertyEvaluationParameters(zoom), false));
}
-TEST(Function, Constant) {
+TEST(CameraFunction, Constant) {
EXPECT_EQ(2.0f, evaluate(PropertyValue<float>(2.0), 0));
EXPECT_EQ(3.8f, evaluate(PropertyValue<float>(3.8), 0));
EXPECT_EQ(22.0f, evaluate(PropertyValue<float>(22.0), 0));
@@ -29,9 +29,9 @@ TEST(Function, Constant) {
EXPECT_EQ(22.0f, evaluate(PropertyValue<float>(22.0), 22));
}
-TEST(Function, Stops) {
+TEST(CameraFunction, Stops) {
// Explicit constant slope in fringe regions.
- Function<float> slope_1({ { 0, 1.5 }, { 6, 1.5 }, { 8, 3 }, { 22, 3 } }, 1.75);
+ CameraFunction<float> slope_1(ExponentialStops<float> { { { 0, 1.5 }, { 6, 1.5 }, { 8, 3 }, { 22, 3 } }, 1.75});
EXPECT_EQ(1.5, evaluate(slope_1, 0));
EXPECT_EQ(1.5, evaluate(slope_1, 4));
EXPECT_EQ(1.5, evaluate(slope_1, 6));
@@ -43,7 +43,7 @@ TEST(Function, Stops) {
// Test constant values in fringe regions.
- Function<float> slope_2({ { 6, 1.5 }, { 8, 3 } }, 1.75);
+ CameraFunction<float> slope_2(ExponentialStops<float> { { { 6, 1.5 }, { 8, 3 } }, 1.75 });
EXPECT_EQ(1.5, evaluate(slope_2, 0));
EXPECT_EQ(1.5, evaluate(slope_2, 4));
EXPECT_EQ(1.5, evaluate(slope_2, 6));
@@ -55,7 +55,7 @@ TEST(Function, Stops) {
// Explicit constant slope in fringe regions.
- Function<float> slope_4({ { 0, 2 }, { 8, 10 } }, 1);
+ CameraFunction<float> slope_4(ExponentialStops<float> { { { 0, 2 }, { 8, 10 } }, 1 });
EXPECT_EQ(2, evaluate(slope_4, 0));
EXPECT_EQ(3, evaluate(slope_4, 1));
EXPECT_EQ(4, evaluate(slope_4, 2));
@@ -63,14 +63,14 @@ TEST(Function, Stops) {
EXPECT_EQ(10, evaluate(slope_4, 8));
// discrete values
- Function<std::string> discrete_0({{3, "string0"}, {6, "string1"}, {9, "string2"}}, 1);
+ CameraFunction<std::string> discrete_0(IntervalStops<std::string> { {{3, "string0"}, {6, "string1"}, {9, "string2"}} });
EXPECT_EQ("string0", evaluate(discrete_0, 2));
EXPECT_EQ("string0", evaluate(discrete_0, 4));
EXPECT_EQ("string1", evaluate(discrete_0, 7));
EXPECT_EQ("string2", evaluate(discrete_0, 9));
EXPECT_EQ("string2", evaluate(discrete_0, 10));
- Function<bool> discreteBool({{1, false}, {3, true}}, 1);
+ CameraFunction<bool> discreteBool(IntervalStops<bool> { {{1, false}, {3, true}} });
EXPECT_FALSE(evaluate(discreteBool, 0));
EXPECT_FALSE(evaluate(discreteBool, 1));
EXPECT_FALSE(evaluate(discreteBool, 2));
diff --git a/test/style/function/source_function.test.cpp b/test/style/function/source_function.test.cpp
new file mode 100644
index 0000000000..260620c8d0
--- /dev/null
+++ b/test/style/function/source_function.test.cpp
@@ -0,0 +1,94 @@
+#include <mbgl/test/util.hpp>
+#include <mbgl/test/stub_geometry_tile_feature.hpp>
+
+#include <mbgl/style/function/source_function.hpp>
+
+using namespace mbgl;
+using namespace mbgl::style;
+
+using namespace std::string_literals;
+
+static StubGeometryTileFeature oneInteger {
+ PropertyMap {{ "property", uint64_t(1) }}
+};
+
+static StubGeometryTileFeature oneDouble {
+ PropertyMap {{ "property", 1.0 }}
+};
+
+static StubGeometryTileFeature oneString {
+ PropertyMap {{ "property", "1"s }}
+};
+
+static StubGeometryTileFeature red {
+ PropertyMap {{ "property", "red"s }}
+};
+
+static StubGeometryTileFeature oneTwoInteger {
+ PropertyMap {{ "property", std::vector<Value>({uint64_t(1), uint64_t(2)}) }}
+};
+
+static StubGeometryTileFeature oneTwoDouble {
+ PropertyMap {{ "property", std::vector<Value>({1.0, 2.0}) }}
+};
+
+static StubGeometryTileFeature oneTwoString {
+ PropertyMap {{ "property", std::vector<Value>({"1"s, "2"s}) }}
+};
+
+static StubGeometryTileFeature trueFeature {
+ PropertyMap {{ "property", true }}
+};
+
+static StubGeometryTileFeature falseFeature {
+ PropertyMap {{ "property", false }}
+};
+
+TEST(SourceFunction, Identity) {
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneInteger, 2.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneDouble, 2.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", IdentityStops<float>(), 0.0f)
+ .evaluate(oneString, 2.0f));
+ EXPECT_EQ(2.0f, SourceFunction<float>("property", IdentityStops<float>())
+ .evaluate(oneString, 2.0f));
+
+ EXPECT_EQ(Color::red(), SourceFunction<Color>("property", IdentityStops<Color>(), Color::black())
+ .evaluate(red, Color::black()));
+ EXPECT_EQ(Color::black(), SourceFunction<Color>("property", IdentityStops<Color>(), Color::black())
+ .evaluate(oneInteger, Color::black()));
+
+ std::array<float, 2> zeroArray {{ 0, 0 }};
+ EXPECT_EQ((std::array<float, 2> {{ 1, 2 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoInteger, zeroArray)));
+ EXPECT_EQ((std::array<float, 2> {{ 1, 2 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoDouble, zeroArray)));
+ EXPECT_EQ((std::array<float, 2> {{ 0, 0 }}), (SourceFunction<std::array<float, 2>>("property", IdentityStops<std::array<float, 2>>(), zeroArray)
+ .evaluate(oneTwoString, zeroArray)));
+}
+
+TEST(SourceFunction, Categorical) {
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneInteger, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneDouble, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ int64_t(1), 1.0f }}))
+ .evaluate(oneString, 0.0f));
+
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneInteger, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneDouble, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ "1"s, 1.0f }}))
+ .evaluate(oneString, 0.0f));
+
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ true, 1.0f }}))
+ .evaluate(trueFeature, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ true, 1.0f }}))
+ .evaluate(falseFeature, 0.0f));
+ EXPECT_EQ(0.0f, SourceFunction<float>("property", CategoricalStops<float>({{ false, 1.0f }}))
+ .evaluate(trueFeature, 0.0f));
+ EXPECT_EQ(1.0f, SourceFunction<float>("property", CategoricalStops<float>({{ false, 1.0f }}))
+ .evaluate(falseFeature, 0.0f));
+}
diff --git a/test/style/paint_property.test.cpp b/test/style/paint_property.test.cpp
index 487dbe9652..c70fa101ca 100644
--- a/test/style/paint_property.test.cpp
+++ b/test/style/paint_property.test.cpp
@@ -6,54 +6,59 @@ using namespace mbgl;
using namespace mbgl::style;
using namespace std::literals::chrono_literals;
+float evaluate(UnevaluatedPaintProperty<PropertyValue<float>>& property, Duration delta = Duration::zero()) {
+ PropertyEvaluationParameters parameters {
+ 0,
+ TimePoint::min() + delta,
+ ZoomHistory(),
+ Duration::zero()
+ };
+
+ PropertyEvaluator<float> evaluator {
+ parameters,
+ 0.0f
+ };
+
+ return property.evaluate(evaluator, parameters.now);
+}
+
TEST(UnevaluatedPaintProperty, EvaluateDefaultValue) {
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> property;
- ASSERT_EQ(0.0f, property.evaluate(PropertyEvaluationParameters(0), 0.0f));
+ UnevaluatedPaintProperty<PropertyValue<float>> property;
+ ASSERT_EQ(0.0f, evaluate(property));
}
TEST(UnevaluatedPaintProperty, EvaluateUntransitionedConstant) {
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> property {
+ UnevaluatedPaintProperty<PropertyValue<float>> property {
PropertyValue<float>(1.0f),
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>>(),
+ UnevaluatedPaintProperty<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
- ASSERT_EQ(1.0f, property.evaluate(PropertyEvaluationParameters(0), 0.0f));
+ ASSERT_EQ(1.0f, evaluate(property));
}
TEST(UnevaluatedPaintProperty, EvaluateTransitionedConstantWithoutDelay) {
TransitionOptions transition;
transition.duration = { 1000ms };
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> t0 {
+ UnevaluatedPaintProperty<PropertyValue<float>> t0 {
PropertyValue<float>(0.0f),
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>>(),
+ UnevaluatedPaintProperty<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> t1 {
+ UnevaluatedPaintProperty<PropertyValue<float>> t1 {
PropertyValue<float>(1.0f),
t0,
transition,
TimePoint::min()
};
- auto evaluate = [&] (Duration delta) {
- PropertyEvaluationParameters parameters {
- 0,
- TimePoint::min() + delta,
- ZoomHistory(),
- Duration::zero()
- };
-
- return t1.evaluate(parameters, 0.0f);
- };
-
- ASSERT_FLOAT_EQ(0.0f, evaluate(0ms));
- ASSERT_FLOAT_EQ(0.823099f, evaluate(500ms));
- ASSERT_FLOAT_EQ(1.0f, evaluate(1500ms));
+ ASSERT_FLOAT_EQ(0.0f, evaluate(t1, 0ms));
+ ASSERT_FLOAT_EQ(0.823099f, evaluate(t1, 500ms));
+ ASSERT_FLOAT_EQ(1.0f, evaluate(t1, 1500ms));
}
TEST(UnevaluatedPaintProperty, EvaluateTransitionedConstantWithDelay) {
@@ -61,34 +66,23 @@ TEST(UnevaluatedPaintProperty, EvaluateTransitionedConstantWithDelay) {
transition.delay = { 1000ms };
transition.duration = { 1000ms };
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> t0 {
+ UnevaluatedPaintProperty<PropertyValue<float>> t0 {
PropertyValue<float>(0.0f),
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>>(),
+ UnevaluatedPaintProperty<PropertyValue<float>>(),
TransitionOptions(),
TimePoint::min()
};
- UnevaluatedPaintProperty<float, PropertyEvaluator<float>> t1 {
+ UnevaluatedPaintProperty<PropertyValue<float>> t1 {
PropertyValue<float>(1.0f),
t0,
transition,
TimePoint::min()
};
- auto evaluate = [&] (Duration delta) {
- PropertyEvaluationParameters parameters {
- 0,
- TimePoint::min() + delta,
- ZoomHistory(),
- Duration::zero()
- };
-
- return t1.evaluate(parameters, 0.0f);
- };
-
- ASSERT_FLOAT_EQ(0.0f, evaluate(0ms));
- ASSERT_FLOAT_EQ(0.0f, evaluate(500ms));
- ASSERT_FLOAT_EQ(0.0f, evaluate(612ms));
- ASSERT_FLOAT_EQ(0.823099f, evaluate(1500ms));
- ASSERT_FLOAT_EQ(1.0f, evaluate(2500ms));
+ ASSERT_FLOAT_EQ(0.0f, evaluate(t1, 0ms));
+ ASSERT_FLOAT_EQ(0.0f, evaluate(t1, 500ms));
+ ASSERT_FLOAT_EQ(0.0f, evaluate(t1, 612ms));
+ ASSERT_FLOAT_EQ(0.823099f, evaluate(t1, 1500ms));
+ ASSERT_FLOAT_EQ(1.0f, evaluate(t1, 2500ms));
}
diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp
index 01f54d6b18..fb7737e417 100644
--- a/test/style/source.test.cpp
+++ b/test/style/source.test.cpp
@@ -393,7 +393,7 @@ TEST(Source, GeoJSonSourceUrlUpdate) {
};
test.observer.sourceDescriptionChanged = [&] (Source&) {
- //Should be called (test will hang if it doesn't)
+ // Should be called (test will hang if it doesn't)
test.end();
};
@@ -404,12 +404,12 @@ TEST(Source, GeoJSonSourceUrlUpdate) {
GeoJSONSource source("source");
source.baseImpl->setObserver(&test.observer);
- //Load initial, so the source state will be loaded=true
+ // Load initial, so the source state will be loaded=true
source.baseImpl->loadDescription(test.fileSource);
- //Schedule an update
+ // Schedule an update
test.loop.invoke([&] () {
- //Update the url
+ // Update the url
source.setURL(std::string("http://source-url.ext"));
});
diff --git a/test/style/style.test.cpp b/test/style/style.test.cpp
index 89c5c4ce6f..b49058420e 100644
--- a/test/style/style.test.cpp
+++ b/test/style/style.test.cpp
@@ -131,6 +131,6 @@ TEST(Style, DuplicateSource) {
style.addSource(std::make_unique<VectorSource>("sourceId", "mapbox://mapbox.mapbox-terrain-v2"));
FAIL() << "Should not have been allowed to add a duplicate source id";
} catch (std::runtime_error) {
- //Expected
+ // Expected
}
}
diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp
index 8356f3accd..10b88c53d4 100644
--- a/test/style/style_layer.test.cpp
+++ b/test/style/style_layer.test.cpp
@@ -36,27 +36,27 @@ template <class T, class... Params> void testClone(Params... params) {
EXPECT_EQ("test", layer->baseImpl->clone()->getID());
}
-const auto color = PropertyValue<Color> {{ 1, 0, 0, 1 }};
-const auto opacity = PropertyValue<float> { 1.0f };
-const auto radius = PropertyValue<float> { 1.0f };
-const auto blur = PropertyValue<float> { 1.0f };
-const auto pattern = PropertyValue<std::string> { "foo" };
-const auto antialias = PropertyValue<bool> { false };
-const auto translate = PropertyValue<std::array<float, 2>> {{{ 0, 0 }}};
-const auto translateAnchor = PropertyValue<TranslateAnchorType> { TranslateAnchorType::Map };
-const auto lineCap = PropertyValue<LineCapType> { LineCapType::Round };
-const auto lineJoin = PropertyValue<LineJoinType> { LineJoinType::Miter };
-const auto miterLimit = PropertyValue<float> { 1.0f };
-const auto roundLimit = PropertyValue<float> { 1.0f };
-const auto width = PropertyValue<float> { 1.0f };
-const auto gapWidth = PropertyValue<float> { 1.0f };
-const auto offset = PropertyValue<float> { 1.0f };
-const auto dashArray = PropertyValue<std::vector<float>> {{}};
-const auto hueRotate = PropertyValue<float> { 1.0f };
-const auto brightness = PropertyValue<float> { 1.0f };
-const auto saturation = PropertyValue<float> { 1.0f };
-const auto contrast = PropertyValue<float> { 1.0f };
-const auto duration = PropertyValue<float> { 1.0f };
+const auto color = Color { 1, 0, 0, 1 };
+const auto opacity = 1.0f;
+const auto radius = 1.0f;
+const auto blur = 1.0f;
+const auto pattern = std::string { "foo" };
+const auto antialias = false;
+const auto translate = std::array<float, 2> {{ 0, 0 }};
+const auto translateAnchor = TranslateAnchorType::Map;
+const auto lineCap = LineCapType::Round;
+const auto lineJoin = LineJoinType::Miter;
+const auto miterLimit = 1.0f;
+const auto roundLimit = 1.0f;
+const auto width = 1.0f;
+const auto gapWidth = 1.0f;
+const auto offset = 1.0f;
+const auto dashArray = std::vector<float> {};
+const auto hueRotate = 1.0f;
+const auto brightness = 1.0f;
+const auto saturation = 1.0f;
+const auto contrast = 1.0f;
+const auto duration = 1.0f;
} // namespace
@@ -77,13 +77,13 @@ TEST(Layer, BackgroundProperties) {
// Paint properties
layer->setBackgroundColor(color);
- EXPECT_EQ(layer->getBackgroundColor().asConstant(), color.asConstant());
+ EXPECT_EQ(layer->getBackgroundColor(), color);
layer->setBackgroundOpacity(opacity);
- EXPECT_EQ(layer->getBackgroundOpacity().asConstant(), opacity.asConstant());
+ EXPECT_EQ(layer->getBackgroundOpacity(), opacity);
layer->setBackgroundPattern(pattern);
- EXPECT_EQ(layer->getBackgroundPattern().asConstant(), pattern.asConstant());
+ EXPECT_EQ(layer->getBackgroundPattern(), pattern);
}
TEST(Layer, CircleProperties) {
@@ -93,22 +93,22 @@ TEST(Layer, CircleProperties) {
// Paint properties
layer->setCircleColor(color);
- EXPECT_EQ(layer->getCircleColor().asConstant(), color.asConstant());
+ EXPECT_EQ(layer->getCircleColor(), color);
layer->setCircleOpacity(opacity);
- EXPECT_EQ(layer->getCircleOpacity().asConstant(), opacity.asConstant());
+ EXPECT_EQ(layer->getCircleOpacity(), opacity);
layer->setCircleRadius(radius);
- EXPECT_EQ(layer->getCircleRadius().asConstant(), radius.asConstant());
+ EXPECT_EQ(layer->getCircleRadius(), radius);
layer->setCircleBlur(blur);
- EXPECT_EQ(layer->getCircleBlur().asConstant(), blur.asConstant());
+ EXPECT_EQ(layer->getCircleBlur(), blur);
layer->setCircleTranslate(translate);
- EXPECT_EQ(layer->getCircleTranslate().asConstant(), translate.asConstant());
+ EXPECT_EQ(layer->getCircleTranslate(), translate);
layer->setCircleTranslateAnchor(translateAnchor);
- EXPECT_EQ(layer->getCircleTranslateAnchor().asConstant(), translateAnchor.asConstant());
+ EXPECT_EQ(layer->getCircleTranslateAnchor(), translateAnchor);
}
TEST(Layer, FillProperties) {
@@ -118,25 +118,25 @@ TEST(Layer, FillProperties) {
// Paint properties
layer->setFillColor(color);
- EXPECT_EQ(layer->getFillColor().asConstant(), color.asConstant());
+ EXPECT_EQ(layer->getFillColor(), color);
layer->setFillOutlineColor(color);
- EXPECT_EQ(layer->getFillOutlineColor().asConstant(), color.asConstant());
+ EXPECT_EQ(layer->getFillOutlineColor(), color);
layer->setFillOpacity(opacity);
- EXPECT_EQ(layer->getFillOpacity().asConstant(), opacity.asConstant());
+ EXPECT_EQ(layer->getFillOpacity(), opacity);
layer->setFillPattern(pattern);
- EXPECT_EQ(layer->getFillPattern().asConstant(), pattern.asConstant());
+ EXPECT_EQ(layer->getFillPattern(), pattern);
layer->setFillAntialias(antialias);
- EXPECT_EQ(layer->getFillAntialias().asConstant(), antialias.asConstant());
+ EXPECT_EQ(layer->getFillAntialias(), antialias);
layer->setFillTranslate(translate);
- EXPECT_EQ(layer->getFillTranslate().asConstant(), translate.asConstant());
+ EXPECT_EQ(layer->getFillTranslate(), translate);
layer->setFillTranslateAnchor(translateAnchor);
- EXPECT_EQ(layer->getFillTranslateAnchor().asConstant(), translateAnchor.asConstant());
+ EXPECT_EQ(layer->getFillTranslateAnchor(), translateAnchor);
}
TEST(Layer, LineProperties) {
@@ -146,48 +146,48 @@ TEST(Layer, LineProperties) {
// Layout properties
layer->setLineCap(lineCap);
- EXPECT_EQ(layer->getLineCap().asConstant(), lineCap.asConstant());
+ EXPECT_EQ(layer->getLineCap(), lineCap);
layer->setLineJoin(lineJoin);
- EXPECT_EQ(layer->getLineJoin().asConstant(), lineJoin.asConstant());
+ EXPECT_EQ(layer->getLineJoin(), lineJoin);
layer->setLineMiterLimit(miterLimit);
- EXPECT_EQ(layer->getLineMiterLimit().asConstant(), miterLimit.asConstant());
+ EXPECT_EQ(layer->getLineMiterLimit(), miterLimit);
layer->setLineRoundLimit(roundLimit);
- EXPECT_EQ(layer->getLineRoundLimit().asConstant(), roundLimit.asConstant());
+ EXPECT_EQ(layer->getLineRoundLimit(), roundLimit);
// Paint properties
layer->setLineColor(color);
- EXPECT_EQ(layer->getLineColor().asConstant(), color.asConstant());
+ EXPECT_EQ(layer->getLineColor(), color);
layer->setLineOpacity(opacity);
- EXPECT_EQ(layer->getLineOpacity().asConstant(), opacity.asConstant());
+ EXPECT_EQ(layer->getLineOpacity(), opacity);
layer->setLineTranslate(translate);
- EXPECT_EQ(layer->getLineTranslate().asConstant(), translate.asConstant());
+ EXPECT_EQ(layer->getLineTranslate(), translate);
layer->setLineTranslateAnchor(translateAnchor);
- EXPECT_EQ(layer->getLineTranslateAnchor().asConstant(), translateAnchor.asConstant());
+ EXPECT_EQ(layer->getLineTranslateAnchor(), translateAnchor);
layer->setLineWidth(width);
- EXPECT_EQ(layer->getLineWidth().asConstant(), width.asConstant());
+ EXPECT_EQ(layer->getLineWidth(), width);
layer->setLineGapWidth(gapWidth);
- EXPECT_EQ(layer->getLineGapWidth().asConstant(), gapWidth.asConstant());
+ EXPECT_EQ(layer->getLineGapWidth(), gapWidth);
layer->setLineOffset(offset);
- EXPECT_EQ(layer->getLineOffset().asConstant(), offset.asConstant());
+ EXPECT_EQ(layer->getLineOffset(), offset);
layer->setLineBlur(blur);
- EXPECT_EQ(layer->getLineBlur().asConstant(), blur.asConstant());
+ EXPECT_EQ(layer->getLineBlur(), blur);
layer->setLineDasharray(dashArray);
- EXPECT_EQ(layer->getLineDasharray().asConstant(), dashArray.asConstant());
+ EXPECT_EQ(layer->getLineDasharray(), dashArray);
layer->setLinePattern(pattern);
- EXPECT_EQ(layer->getLinePattern().asConstant(), pattern.asConstant());
+ EXPECT_EQ(layer->getLinePattern(), pattern);
}
TEST(Layer, RasterProperties) {
@@ -197,25 +197,25 @@ TEST(Layer, RasterProperties) {
// Paint properties
layer->setRasterOpacity(opacity);
- EXPECT_EQ(layer->getRasterOpacity().asConstant(), opacity.asConstant());
+ EXPECT_EQ(layer->getRasterOpacity(), opacity);
layer->setRasterHueRotate(hueRotate);
- EXPECT_EQ(layer->getRasterHueRotate().asConstant(), hueRotate.asConstant());
+ EXPECT_EQ(layer->getRasterHueRotate(), hueRotate);
layer->setRasterBrightnessMin(brightness);
- EXPECT_EQ(layer->getRasterBrightnessMin().asConstant(), brightness.asConstant());
+ EXPECT_EQ(layer->getRasterBrightnessMin(), brightness);
layer->setRasterBrightnessMax(brightness);
- EXPECT_EQ(layer->getRasterBrightnessMax().asConstant(), brightness.asConstant());
+ EXPECT_EQ(layer->getRasterBrightnessMax(), brightness);
layer->setRasterSaturation(saturation);
- EXPECT_EQ(layer->getRasterSaturation().asConstant(), saturation.asConstant());
+ EXPECT_EQ(layer->getRasterSaturation(), saturation);
layer->setRasterContrast(contrast);
- EXPECT_EQ(layer->getRasterContrast().asConstant(), contrast.asConstant());
+ EXPECT_EQ(layer->getRasterContrast(), contrast);
layer->setRasterFadeDuration(duration);
- EXPECT_EQ(layer->getRasterFadeDuration().asConstant(), duration.asConstant());
+ EXPECT_EQ(layer->getRasterFadeDuration(), duration);
}
TEST(Layer, Observer) {
@@ -278,20 +278,20 @@ TEST(Layer, Observer) {
TEST(Layer, DuplicateLayer) {
util::RunLoop loop;
- //Setup style
+ // Setup style
StubFileSource fileSource;
Style style { fileSource, 1.0 };
style.setJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
- //Add initial layer
+ // Add initial layer
style.addLayer(std::make_unique<LineLayer>("line", "unusedsource"));
- //Try to add duplicate
+ // Try to add duplicate
try {
style.addLayer(std::make_unique<LineLayer>("line", "unusedsource"));
FAIL() << "Should not have been allowed to add a duplicate layer id";
} catch (const std::runtime_error e) {
- //Expected
+ // Expected
ASSERT_STREQ("Layer line already exists", e.what());
}
}
diff --git a/test/text/glyph_atlas.test.cpp b/test/text/glyph_atlas.test.cpp
index e229cd117b..3679cabc1b 100644
--- a/test/text/glyph_atlas.test.cpp
+++ b/test/text/glyph_atlas.test.cpp
@@ -83,8 +83,7 @@ TEST(GlyphAtlas, LoadingFail) {
EXPECT_TRUE(error != nullptr);
EXPECT_EQ(util::toString(error), "Failed by the test case");
- auto glyphSet = test.glyphAtlas.getGlyphSet({{"Test Stack"}});
- ASSERT_TRUE(glyphSet->getSDFs().empty());
+ ASSERT_TRUE(test.glyphAtlas.getGlyphSet({{"Test Stack"}})->getSDFs().empty());
ASSERT_FALSE(test.glyphAtlas.hasGlyphRanges({{"Test Stack"}}, {{0, 255}}));
test.end();
@@ -112,8 +111,7 @@ TEST(GlyphAtlas, LoadingCorrupted) {
EXPECT_TRUE(error != nullptr);
EXPECT_EQ(util::toString(error), "unknown pbf field type exception");
- auto glyphSet = test.glyphAtlas.getGlyphSet({{"Test Stack"}});
- ASSERT_TRUE(glyphSet->getSDFs().empty());
+ ASSERT_TRUE(test.glyphAtlas.getGlyphSet({{"Test Stack"}})->getSDFs().empty());
ASSERT_FALSE(test.glyphAtlas.hasGlyphRanges({{"Test Stack"}}, {{0, 255}}));
test.end();
@@ -144,32 +142,27 @@ TEST(GlyphAtlas, LoadingCancel) {
}
TEST(GlyphAtlas, InvalidSDFGlyph) {
- GlyphSet glyphSet;
- glyphSet.insert(65, SDFGlyph{ 65 /* ASCII 'A' */,
- "x" /* bitmap is too short */,
- { 1 /* width */, 1 /* height */, 0 /* left */, 0 /* top */,
- 0 /* advance */ } });
- glyphSet.insert(66, SDFGlyph{ 66 /* ASCII 'B' */,
- std::string(7 * 7, 'x'), /* correct */
+ const FontStack fontStack{ "Mock Font" };
+
+ GlyphAtlasTest test;
+ GlyphPositions positions;
+
+ auto glyphSet = test.glyphAtlas.getGlyphSet(fontStack);
+ glyphSet->insert(66, SDFGlyph{ 66 /* ASCII 'B' */,
+ AlphaImage({7, 7}), /* correct */
{ 1 /* width */, 1 /* height */, 0 /* left */, 0 /* top */,
0 /* advance */ } });
- glyphSet.insert(67, SDFGlyph{ 67 /* ASCII 'C' */,
- std::string(518 * 8, 'x'), /* correct */
+ glyphSet->insert(67, SDFGlyph{ 67 /* ASCII 'C' */,
+ AlphaImage({518, 8}), /* correct */
{ 512 /* width */, 2 /* height */, 0 /* left */, 0 /* top */,
0 /* advance */ } });
-
- const FontStack fontStack{ "Mock Font" };
-
- GlyphAtlasTest test;
- GlyphPositions positions;
test.glyphAtlas.addGlyphs(1, std::u16string{u"ABC"}, fontStack, glyphSet, positions);
- ASSERT_EQ(3u, positions.size());
+ ASSERT_EQ(2u, positions.size());
- // 'A' was not placed because the bitmap size is invalid.
- ASSERT_NE(positions.end(), positions.find(65));
- ASSERT_EQ((Rect<uint16_t>{ 0, 0, 0, 0 }), positions[65].rect);
+ // 'A' was not placed because not in the glyph set.
+ ASSERT_EQ(positions.end(), positions.find(65));
// 'B' was placed at the top left.
ASSERT_NE(positions.end(), positions.find(66));
diff --git a/test/text/glyph_pbf.test.cpp b/test/text/glyph_pbf.test.cpp
index 1e28dfbc31..be3ca3359b 100644
--- a/test/text/glyph_pbf.test.cpp
+++ b/test/text/glyph_pbf.test.cpp
@@ -44,15 +44,17 @@ TEST(GlyphPBF, Parsing) {
glyphAtlasObserver.glyphsLoaded = [&](const FontStack&, const GlyphRange&) {
loop.stop();
- auto sdfs = glyphAtlas.getGlyphSet(fontStack)->getSDFs();
+ const auto& sdfs = glyphAtlas.getGlyphSet(fontStack)->getSDFs();
// The fake glyphs don't contain a glyph that has the ID 0; it only contains glyphs with
// undefined IDs, but the parser should remove them.
EXPECT_TRUE(sdfs.size() == 1);
EXPECT_TRUE(sdfs.find(69) != sdfs.end());
- auto& sdf = sdfs[69];
- EXPECT_EQ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"s, sdf.bitmap);
+ auto& sdf = sdfs.at(69);
+ AlphaImage expected({7, 7});
+ expected.fill('x');
+ EXPECT_EQ(expected, sdf.bitmap);
EXPECT_EQ(1u, sdf.metrics.width);
EXPECT_EQ(1u, sdf.metrics.height);
EXPECT_EQ(20, sdf.metrics.left);
diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp
index c20218a82f..42bc0f2048 100644
--- a/test/text/quads.test.cpp
+++ b/test/text/quads.test.cpp
@@ -14,68 +14,68 @@ TEST(getIconQuads, normal) {
Anchor anchor(2.0, 3.0, 0.0, 0.5f, 0);
SpriteAtlasElement image = {
Rect<uint16_t>( 0, 0, 15, 11 ),
- std::shared_ptr<const SpriteImage>(),
+ std::make_shared<const SpriteImage>(PremultipliedImage({1,1}), 1.0),
+ { 0, 0 },
1.0f
};
- PositionedIcon shapedIcon(image, -5.0, 6.0, -7.0, 8.0);
+ PositionedIcon shapedIcon(image, -5.0, 6.0, -7.0, 8.0, 0);
GeometryCoordinates line;
Shaping shapedText;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads.size(), 1u);
- ASSERT_EQ(quads[0].anchorPoint.x, 2);
- ASSERT_EQ(quads[0].anchorPoint.y, 3);
- ASSERT_EQ(quads[0].tl.x, -8);
- ASSERT_EQ(quads[0].tl.y, -6);
- ASSERT_EQ(quads[0].tr.x, 7);
- ASSERT_EQ(quads[0].tr.y, -6);
- ASSERT_EQ(quads[0].bl.x, -8);
- ASSERT_EQ(quads[0].bl.y, 5);
- ASSERT_EQ(quads[0].br.x, 7);
- ASSERT_EQ(quads[0].br.y, 5);
- ASSERT_EQ(quads[0].anchorAngle, 0.0f);
- ASSERT_EQ(quads[0].glyphAngle, 0.0f);
- ASSERT_EQ(quads[0].minScale, 0.5f);
+ ASSERT_EQ(quad.anchorPoint.x, 2);
+ ASSERT_EQ(quad.anchorPoint.y, 3);
+ ASSERT_EQ(quad.tl.x, -8);
+ ASSERT_EQ(quad.tl.y, -6);
+ ASSERT_EQ(quad.tr.x, 7);
+ ASSERT_EQ(quad.tr.y, -6);
+ ASSERT_EQ(quad.bl.x, -8);
+ ASSERT_EQ(quad.bl.y, 5);
+ ASSERT_EQ(quad.br.x, 7);
+ ASSERT_EQ(quad.br.y, 5);
+ ASSERT_EQ(quad.anchorAngle, 0.0f);
+ ASSERT_EQ(quad.glyphAngle, 0.0f);
+ ASSERT_EQ(quad.minScale, 0.5f);
}
TEST(getIconQuads, style) {
Anchor anchor(0.0, 0.0, 0.0, 0.5f, 0);
SpriteAtlasElement image = {
Rect<uint16_t>( 0, 0, 20, 20 ),
- std::shared_ptr<const SpriteImage>(),
+ std::make_shared<const SpriteImage>(PremultipliedImage({1,1}), 1.0),
+ { 0, 0 },
1.0f
};
- PositionedIcon shapedIcon(image, -10.0, 10.0, -10.0, 10.0);
+ PositionedIcon shapedIcon(image, -10.0, 10.0, -10.0, 10.0, 0);
GeometryCoordinates line;
Shaping shapedText;
shapedText.top = -10.0f;
shapedText.bottom = 30.0f;
shapedText.left = -60.0f;
shapedText.right = 20.0f;
- shapedText.positionedGlyphs.emplace_back(PositionedGlyph(32, 0.0f, 0.0f));
+ shapedText.positionedGlyphs.emplace_back(PositionedGlyph(32, 0.0f, 0.0f, 0));
// none
{
SymbolLayoutProperties::Evaluated layout;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads.size(), 1u);
- ASSERT_EQ(quads[0].anchorPoint.x, 0);
- ASSERT_EQ(quads[0].anchorPoint.y, 0);
- ASSERT_EQ(quads[0].tl.x, -11);
- ASSERT_EQ(quads[0].tl.y, -11);
- ASSERT_EQ(quads[0].tr.x, 9);
- ASSERT_EQ(quads[0].tr.y, -11);
- ASSERT_EQ(quads[0].bl.x, -11);
- ASSERT_EQ(quads[0].bl.y, 9);
- ASSERT_EQ(quads[0].br.x, 9);
- ASSERT_EQ(quads[0].br.y, 9);
- ASSERT_EQ(quads[0].anchorAngle, 0.0f);
- ASSERT_EQ(quads[0].glyphAngle, 0.0f);
- ASSERT_EQ(quads[0].minScale, 0.5f);
+ ASSERT_EQ(quad.anchorPoint.x, 0);
+ ASSERT_EQ(quad.anchorPoint.y, 0);
+ ASSERT_EQ(quad.tl.x, -11);
+ ASSERT_EQ(quad.tl.y, -11);
+ ASSERT_EQ(quad.tr.x, 9);
+ ASSERT_EQ(quad.tr.y, -11);
+ ASSERT_EQ(quad.bl.x, -11);
+ ASSERT_EQ(quad.bl.y, 9);
+ ASSERT_EQ(quad.br.x, 9);
+ ASSERT_EQ(quad.br.y, 9);
+ ASSERT_EQ(quad.anchorAngle, 0.0f);
+ ASSERT_EQ(quad.glyphAngle, 0.0f);
+ ASSERT_EQ(quad.minScale, 0.5f);
}
// width
@@ -83,17 +83,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -60);
- ASSERT_EQ(quads[0].tl.y, 0);
- ASSERT_EQ(quads[0].tr.x, 20);
- ASSERT_EQ(quads[0].tr.y, 0);
- ASSERT_EQ(quads[0].bl.x, -60);
- ASSERT_EQ(quads[0].bl.y, 20);
- ASSERT_EQ(quads[0].br.x, 20);
- ASSERT_EQ(quads[0].br.y, 20);
+ ASSERT_EQ(quad.tl.x, -60);
+ ASSERT_EQ(quad.tl.y, 0);
+ ASSERT_EQ(quad.tr.x, 20);
+ ASSERT_EQ(quad.tr.y, 0);
+ ASSERT_EQ(quad.bl.x, -60);
+ ASSERT_EQ(quad.bl.y, 20);
+ ASSERT_EQ(quad.br.x, 20);
+ ASSERT_EQ(quad.br.y, 20);
}
// width x textSize
@@ -101,17 +101,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Width;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -30);
- ASSERT_EQ(quads[0].tl.y, -5);
- ASSERT_EQ(quads[0].tr.x, 10);
- ASSERT_EQ(quads[0].tr.y, -5);
- ASSERT_EQ(quads[0].bl.x, -30);
- ASSERT_EQ(quads[0].bl.y, 15);
- ASSERT_EQ(quads[0].br.x, 10);
- ASSERT_EQ(quads[0].br.y, 15);
+ ASSERT_EQ(quad.tl.x, -30);
+ ASSERT_EQ(quad.tl.y, -5);
+ ASSERT_EQ(quad.tr.x, 10);
+ ASSERT_EQ(quad.tr.y, -5);
+ ASSERT_EQ(quad.bl.x, -30);
+ ASSERT_EQ(quad.bl.y, 15);
+ ASSERT_EQ(quad.br.x, 10);
+ ASSERT_EQ(quad.br.y, 15);
}
// width x textSize + padding
@@ -123,17 +123,17 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -40);
- ASSERT_EQ(quads[0].tl.y, -10);
- ASSERT_EQ(quads[0].tr.x, 20);
- ASSERT_EQ(quads[0].tr.y, -10);
- ASSERT_EQ(quads[0].bl.x, -40);
- ASSERT_EQ(quads[0].bl.y, 20);
- ASSERT_EQ(quads[0].br.x, 20);
- ASSERT_EQ(quads[0].br.y, 20);
+ ASSERT_EQ(quad.tl.x, -40);
+ ASSERT_EQ(quad.tl.y, -10);
+ ASSERT_EQ(quad.tr.x, 20);
+ ASSERT_EQ(quad.tr.y, -10);
+ ASSERT_EQ(quad.bl.x, -40);
+ ASSERT_EQ(quad.bl.y, 20);
+ ASSERT_EQ(quad.br.x, 20);
+ ASSERT_EQ(quad.br.y, 20);
}
// height
@@ -141,17 +141,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -30);
- ASSERT_EQ(quads[0].tl.y, -10);
- ASSERT_EQ(quads[0].tr.x, -10);
- ASSERT_EQ(quads[0].tr.y, -10);
- ASSERT_EQ(quads[0].bl.x, -30);
- ASSERT_EQ(quads[0].bl.y, 30);
- ASSERT_EQ(quads[0].br.x, -10);
- ASSERT_EQ(quads[0].br.y, 30);
+ ASSERT_EQ(quad.tl.x, -30);
+ ASSERT_EQ(quad.tl.y, -10);
+ ASSERT_EQ(quad.tr.x, -10);
+ ASSERT_EQ(quad.tr.y, -10);
+ ASSERT_EQ(quad.bl.x, -30);
+ ASSERT_EQ(quad.bl.y, 30);
+ ASSERT_EQ(quad.br.x, -10);
+ ASSERT_EQ(quad.br.y, 30);
}
// height x textSize
@@ -159,17 +159,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Height;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -20);
- ASSERT_EQ(quads[0].tl.y, -5);
- ASSERT_EQ(quads[0].tr.x, 0);
- ASSERT_EQ(quads[0].tr.y, -5);
- ASSERT_EQ(quads[0].bl.x, -20);
- ASSERT_EQ(quads[0].bl.y, 15);
- ASSERT_EQ(quads[0].br.x, 0);
- ASSERT_EQ(quads[0].br.y, 15);
+ ASSERT_EQ(quad.tl.x, -20);
+ ASSERT_EQ(quad.tl.y, -5);
+ ASSERT_EQ(quad.tr.x, 0);
+ ASSERT_EQ(quad.tr.y, -5);
+ ASSERT_EQ(quad.bl.x, -20);
+ ASSERT_EQ(quad.bl.y, 15);
+ ASSERT_EQ(quad.br.x, 0);
+ ASSERT_EQ(quad.br.y, 15);
}
// height x textSize + padding
@@ -181,17 +181,17 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -30);
- ASSERT_EQ(quads[0].tl.y, -10);
- ASSERT_EQ(quads[0].tr.x, 10);
- ASSERT_EQ(quads[0].tr.y, -10);
- ASSERT_EQ(quads[0].bl.x, -30);
- ASSERT_EQ(quads[0].bl.y, 20);
- ASSERT_EQ(quads[0].br.x, 10);
- ASSERT_EQ(quads[0].br.y, 20);
+ ASSERT_EQ(quad.tl.x, -30);
+ ASSERT_EQ(quad.tl.y, -10);
+ ASSERT_EQ(quad.tr.x, 10);
+ ASSERT_EQ(quad.tr.y, -10);
+ ASSERT_EQ(quad.bl.x, -30);
+ ASSERT_EQ(quad.bl.y, 20);
+ ASSERT_EQ(quad.br.x, 10);
+ ASSERT_EQ(quad.br.y, 20);
}
// both
@@ -199,17 +199,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 24.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -60);
- ASSERT_EQ(quads[0].tl.y, -10);
- ASSERT_EQ(quads[0].tr.x, 20);
- ASSERT_EQ(quads[0].tr.y, -10);
- ASSERT_EQ(quads[0].bl.x, -60);
- ASSERT_EQ(quads[0].bl.y, 30);
- ASSERT_EQ(quads[0].br.x, 20);
- ASSERT_EQ(quads[0].br.y, 30);
+ ASSERT_EQ(quad.tl.x, -60);
+ ASSERT_EQ(quad.tl.y, -10);
+ ASSERT_EQ(quad.tr.x, 20);
+ ASSERT_EQ(quad.tr.y, -10);
+ ASSERT_EQ(quad.bl.x, -60);
+ ASSERT_EQ(quad.bl.y, 30);
+ ASSERT_EQ(quad.br.x, 20);
+ ASSERT_EQ(quad.br.y, 30);
}
// both x textSize
@@ -217,17 +217,17 @@ TEST(getIconQuads, style) {
SymbolLayoutProperties::Evaluated layout;
layout.get<TextSize>() = 12.0f;
layout.get<IconTextFit>() = IconTextFitType::Both;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -30);
- ASSERT_EQ(quads[0].tl.y, -5);
- ASSERT_EQ(quads[0].tr.x, 10);
- ASSERT_EQ(quads[0].tr.y, -5);
- ASSERT_EQ(quads[0].bl.x, -30);
- ASSERT_EQ(quads[0].bl.y, 15);
- ASSERT_EQ(quads[0].br.x, 10);
- ASSERT_EQ(quads[0].br.y, 15);
+ ASSERT_EQ(quad.tl.x, -30);
+ ASSERT_EQ(quad.tl.y, -5);
+ ASSERT_EQ(quad.tr.x, 10);
+ ASSERT_EQ(quad.tr.y, -5);
+ ASSERT_EQ(quad.bl.x, -30);
+ ASSERT_EQ(quad.bl.y, 15);
+ ASSERT_EQ(quad.br.x, 10);
+ ASSERT_EQ(quad.br.y, 15);
}
// both x textSize + padding
@@ -239,17 +239,17 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 10.0f;
layout.get<IconTextFitPadding>()[2] = 5.0f;
layout.get<IconTextFitPadding>()[3] = 10.0f;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -40);
- ASSERT_EQ(quads[0].tl.y, -10);
- ASSERT_EQ(quads[0].tr.x, 20);
- ASSERT_EQ(quads[0].tr.y, -10);
- ASSERT_EQ(quads[0].bl.x, -40);
- ASSERT_EQ(quads[0].bl.y, 20);
- ASSERT_EQ(quads[0].br.x, 20);
- ASSERT_EQ(quads[0].br.y, 20);
+ ASSERT_EQ(quad.tl.x, -40);
+ ASSERT_EQ(quad.tl.y, -10);
+ ASSERT_EQ(quad.tr.x, 20);
+ ASSERT_EQ(quad.tr.y, -10);
+ ASSERT_EQ(quad.bl.x, -40);
+ ASSERT_EQ(quad.bl.y, 20);
+ ASSERT_EQ(quad.br.x, 20);
+ ASSERT_EQ(quad.br.y, 20);
}
// both x textSize + padding t/r/b/l
@@ -261,17 +261,17 @@ TEST(getIconQuads, style) {
layout.get<IconTextFitPadding>()[1] = 5.0f;
layout.get<IconTextFitPadding>()[2] = 10.0f;
layout.get<IconTextFitPadding>()[3] = 15.0f;
- SymbolQuads quads =
- getIconQuads(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
+ SymbolQuad quad =
+ getIconQuad(anchor, shapedIcon, line, layout, SymbolPlacementType::Point, shapedText);
- ASSERT_EQ(quads[0].tl.x, -45);
- ASSERT_EQ(quads[0].tl.y, -5);
- ASSERT_EQ(quads[0].tr.x, 15);
- ASSERT_EQ(quads[0].tr.y, -5);
- ASSERT_EQ(quads[0].bl.x, -45);
- ASSERT_EQ(quads[0].bl.y, 25);
- ASSERT_EQ(quads[0].br.x, 15);
- ASSERT_EQ(quads[0].br.y, 25);
+ ASSERT_EQ(quad.tl.x, -45);
+ ASSERT_EQ(quad.tl.y, -5);
+ ASSERT_EQ(quad.tr.x, 15);
+ ASSERT_EQ(quad.tr.y, -5);
+ ASSERT_EQ(quad.bl.x, -45);
+ ASSERT_EQ(quad.bl.y, 25);
+ ASSERT_EQ(quad.br.x, 15);
+ ASSERT_EQ(quad.br.y, 25);
}
}
diff --git a/test/tile/geometry_tile_data.test.cpp b/test/tile/geometry_tile_data.test.cpp
index 6e118d6fd5..f7fe5816ea 100644
--- a/test/tile/geometry_tile_data.test.cpp
+++ b/test/tile/geometry_tile_data.test.cpp
@@ -3,6 +3,18 @@
using namespace mbgl;
+static double _signedArea(const GeometryCoordinates& ring) {
+ double sum = 0;
+
+ for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
+ const GeometryCoordinate& p1 = ring[i];
+ const GeometryCoordinate& p2 = ring[j];
+ sum += (p2.x - p1.x) * (p1.y + p2.y);
+ }
+
+ return sum;
+}
+
TEST(GeometryTileData, classifyRings1) {
std::vector<GeometryCollection> polygons = classifyRings({
{ {0, 0}, {0, 40}, {40, 40}, {40, 0}, {0, 0} }
@@ -59,3 +71,37 @@ TEST(GeometryTileData, limitHoles2) {
ASSERT_EQ(polygon[0][0].x, 0);
ASSERT_EQ(polygon[1][0].x, 10);
}
+
+TEST(GeometryTileData, limitHoles3) {
+ // real world polygon with interior rings with negative areas
+ // that need to be sorted in `limitHoles` by comparing absolute
+ // area not signed
+ GeometryCollection polygon = {
+ { {7336,-248},{7304,-248},{7272,-168},{7176,-200},{7080,-136},{7048,-56},{7128,-8},{7176,-56},{7288,-56},{7316,0},{6918,0},{6904,-40},{6984,-72},{6952,-88},{6952,-168},{6888,-88},{6856,-88},{6856,-8},{6872,0},{6170,0},{6184,-40},{6136,-72},{6104,-56},{6132,0},{6028,0},{6104,-152},{6184,-200},{6206,-256},{6272,-256},{6264,-248},{6248,-120},{6280,-136},{6280,-232},{6288,-256},{6790,-256},{6792,-248},{6800,-256},{7058,-256},{7064,-248},{7096,-256},{7338,-256},{7336,-248} },
+ { {6344,-104},{6264,-8},{6392,-72},{6360,-200},{6344,-104} },
+ { {6744,-24},{6760,-72},{6728,-104},{6744,-24} },
+ { {6616,-104},{6648,-88},{6632,-72},{6664,-56},{6664,-120},{6616,-104} }
+ };
+
+ // make a copy for later testing
+ GeometryCollection original(polygon);
+
+ ASSERT_EQ(polygon.size(), 4u);
+ ASSERT_EQ(_signedArea(polygon.at(0)), 515360); // exterior
+ ASSERT_EQ(_signedArea(polygon.at(1)), -12288); // biggest interior ring
+ ASSERT_EQ(_signedArea(polygon.at(2)), -2048); // smallest interior ring
+ ASSERT_EQ(_signedArea(polygon.at(3)), -3072); // second largest interior ring
+
+ limitHoles(polygon, 2);
+
+ // output: polygon 1 has 1 exterior, 2 interior
+ ASSERT_EQ(polygon.size(), 3u);
+
+ // ensure we've kept the exterior ring
+ ASSERT_EQ(original.at(0), polygon.at(0));
+
+ // ensure we've kept the two largest interior rings
+ ASSERT_EQ(original.at(1), polygon.at(1));
+ ASSERT_EQ(original.at(3), polygon.at(2));
+
+}
diff --git a/test/tile/raster_tile.test.cpp b/test/tile/raster_tile.test.cpp
index 0d599ceae0..5cfc274be0 100644
--- a/test/tile/raster_tile.test.cpp
+++ b/test/tile/raster_tile.test.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/style.hpp>
#include <mbgl/style/update_parameters.hpp>
#include <mbgl/annotation/annotation_manager.hpp>
+#include <mbgl/renderer/raster_bucket.hpp>
using namespace mbgl;
@@ -45,5 +46,19 @@ TEST(RasterTile, onError) {
RasterTileTest test;
RasterTile tile(OverscaledTileID(0, 0, 0), test.updateParameters, test.tileset);
tile.onError(std::make_exception_ptr(std::runtime_error("test")));
+ EXPECT_FALSE(tile.isRenderable());
+}
+
+TEST(RasterTile, onParsed) {
+ RasterTileTest test;
+ RasterTile tile(OverscaledTileID(0, 0, 0), test.updateParameters, test.tileset);
+ tile.onParsed(std::make_unique<RasterBucket>(UnassociatedImage{}));
EXPECT_TRUE(tile.isRenderable());
}
+
+TEST(RasterTile, onParsedEmpty) {
+ RasterTileTest test;
+ RasterTile tile(OverscaledTileID(0, 0, 0), test.updateParameters, test.tileset);
+ tile.onParsed(nullptr);
+ EXPECT_FALSE(tile.isRenderable());
+}
diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp
index e34629bdba..49fdcbd9f8 100644
--- a/test/tile/vector_tile.test.cpp
+++ b/test/tile/vector_tile.test.cpp
@@ -60,8 +60,12 @@ TEST(VectorTile, Issue7615) {
style::SymbolLayer symbolLayer("symbol", "source");
auto symbolBucket = std::make_shared<SymbolBucket>(
- MapMode::Continuous, style::SymbolLayoutProperties::Evaluated(), false, false);
-
+ style::SymbolLayoutProperties::Evaluated(),
+ std::unordered_map<
+ std::string,
+ std::pair<style::IconPaintProperties::Evaluated, style::TextPaintProperties::Evaluated>>(),
+ 0.0f, false, false);
+
// Simulate placement of a symbol layer.
tile.onPlacement(GeometryTile::PlacementResult {
{{
diff --git a/test/util/http_timeout.test.cpp b/test/util/http_timeout.test.cpp
index e99c703159..c9373d955d 100644
--- a/test/util/http_timeout.test.cpp
+++ b/test/util/http_timeout.test.cpp
@@ -2,22 +2,25 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/http_timeout.hpp>
-#include <regex>
-#include <iostream>
using namespace mbgl;
using namespace mbgl::http;
TEST(HttpRetry, OtherError) {
- //Non-retryable
+ // Non-retryable
ASSERT_EQ(Duration::max(), errorRetryTimeout(Response::Error::Reason::Other, 1));
}
+TEST(HttpRetry, NotFound) {
+ // Non-retryable
+ ASSERT_EQ(Duration::max(), errorRetryTimeout(Response::Error::Reason::NotFound, 1));
+}
+
TEST(HttpRetry, ServerError) {
// 1-3 failures -> 1 sec
ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 1));
ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 3));
-
+
// After 3, exponential backoff
ASSERT_EQ(Seconds(2), errorRetryTimeout(Response::Error::Reason::Server, 4));
ASSERT_EQ(Seconds(1u << 31), errorRetryTimeout(Response::Error::Reason::Server, 50));
@@ -32,8 +35,8 @@ TEST(HttpRetry, ConnectionError) {
TEST(HttpRetry, RateLimit) {
// Pre-set value from header
ASSERT_EQ(Seconds(1), errorRetryTimeout(Response::Error::Reason::Server, 1, { util::now() + Seconds(1) }));
-
- //Default
+
+ // Default
ASSERT_EQ(Seconds(5), errorRetryTimeout(Response::Error::Reason::RateLimit, 1, {}));
}
diff --git a/test/util/image.test.cpp b/test/util/image.test.cpp
index b15ddc1b3f..0cd4a7d8af 100644
--- a/test/util/image.test.cpp
+++ b/test/util/image.test.cpp
@@ -86,6 +86,35 @@ TEST(Image, WebPTile) {
}
#endif // !defined(__ANDROID__) && !defined(__APPLE__) && !defined(QT_IMAGE_DECODERS)
+TEST(Image, Copy) {
+ PremultipliedImage src5({5, 5});
+ PremultipliedImage dst5({5, 5});
+ PremultipliedImage src10({10, 10});
+ PremultipliedImage dst10({10, 10});
+
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {5, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src5, dst10, {1, 1}, {0, 0}, {0, 5}), std::out_of_range);
+
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {6, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {0, 0}, {0, 6}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {5, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst5, {0, 0}, {1, 1}, {0, 5}), std::out_of_range);
+
+ const uint32_t max = std::numeric_limits<uint32_t>::max();
+
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {max, 0}, {0, 0}, {1, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, max}, {0, 0}, {0, 1}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {max, 0}, {1, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, max}, {0, 1}), std::out_of_range);
+
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {1, 0}, {0, 0}, {max, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 1}, {0, 0}, {0, max}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {1, 0}, {max, 0}), std::out_of_range);
+ EXPECT_THROW(PremultipliedImage::copy(src10, dst10, {0, 0}, {0, 1}, {0, max}), std::out_of_range);
+}
+
TEST(Image, Premultiply) {
UnassociatedImage rgba({ 1, 1 });
rgba.data[0] = 255;
diff --git a/test/util/mapbox.test.cpp b/test/util/mapbox.test.cpp
index 452106d6e6..299f0df833 100644
--- a/test/util/mapbox.test.cpp
+++ b/test/util/mapbox.test.cpp
@@ -3,8 +3,7 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/constants.hpp>
-#include <regex>
-#include <iostream>
+#include <stdexcept>
using namespace mbgl;
diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp
index 984e7a3e24..d49c49018f 100644
--- a/test/util/memory.test.cpp
+++ b/test/util/memory.test.cpp
@@ -1,4 +1,5 @@
#include <mbgl/test/stub_file_source.hpp>
+#include <mbgl/test/getrss.hpp>
#include <mbgl/test/util.hpp>
#include <mbgl/map/map.hpp>
@@ -21,29 +22,6 @@
using namespace mbgl;
using namespace std::literals::string_literals;
-long getRSS() {
- auto statm = util::read_file("/proc/self/statm");
-
- std::vector<std::string> stats;
- std::istringstream stream(statm);
-
- std::copy(std::istream_iterator<std::string>(stream),
- std::istream_iterator<std::string>(),
- std::back_inserter(stats));
-
- return std::stol(stats[1]) * getpagesize();
-}
-
-bool isUsingJemalloc() {
- const char* preload = getenv("LD_PRELOAD");
-
- if (preload) {
- return std::string(preload).find("libjemalloc.so") != std::string::npos;
- } else {
- return false;
- }
-}
-
class MemoryTest {
public:
MemoryTest() {
@@ -109,16 +87,31 @@ TEST(Memory, Raster) {
test::render(map, test.view);
}
+/**
+On CI, we only run the memory footprint test in the Qt build, because it uses
+jemalloc, which yields more consistent memory usage results. To force it to
+run locally, use `DO_MEMORY_FOOTPRINT=1 make run-test-Memory.Footprint.
+*/
+bool shouldRunFootprint() {
+ const char* preload = getenv("LD_PRELOAD");
+
+ if (preload) {
+ return std::string(preload).find("libjemalloc.so") != std::string::npos;
+ } else {
+ return getenv("DO_MEMORY_FOOTPRINT");
+ }
+}
+
// This test will measure the size of a Map object
// after rendering a raster and a vector style. The
// idea is to try to keep the memory footprint within
// reasonable limits, so this test acts more like a
// safeguard.
TEST(Memory, Footprint) {
- if (!isUsingJemalloc()) {
+ if (!shouldRunFootprint()) {
return;
}
-
+
MemoryTest test;
auto renderMap = [&](Map& map, const char* style){
@@ -141,7 +134,7 @@ TEST(Memory, Footprint) {
std::vector<std::unique_ptr<Map>> maps;
unsigned runs = 15;
- long vectorInitialRSS = getRSS();
+ long vectorInitialRSS = mbgl::test::getCurrentRSS();
for (unsigned i = 0; i < runs; ++i) {
auto vector = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource,
test.threadPool, MapMode::Still);
@@ -149,9 +142,9 @@ TEST(Memory, Footprint) {
maps.push_back(std::move(vector));
};
- double vectorFootprint = (getRSS() - vectorInitialRSS) / double(runs);
+ double vectorFootprint = (mbgl::test::getCurrentRSS() - vectorInitialRSS) / double(runs);
- long rasterInitialRSS = getRSS();
+ long rasterInitialRSS = mbgl::test::getCurrentRSS();
for (unsigned i = 0; i < runs; ++i) {
auto raster = std::make_unique<Map>(test.backend, Size{ 256, 256 }, 2, test.fileSource,
test.threadPool, MapMode::Still);
@@ -159,7 +152,10 @@ TEST(Memory, Footprint) {
maps.push_back(std::move(raster));
};
- double rasterFootprint = (getRSS() - rasterInitialRSS) / double(runs);
+ double rasterFootprint = (mbgl::test::getCurrentRSS() - rasterInitialRSS) / double(runs);
+
+ RecordProperty("vectorFootprint", vectorFootprint);
+ RecordProperty("rasterFootprint", rasterFootprint);
ASSERT_LT(vectorFootprint, 65 * 1024 * 1024) << "\
mbgl::Map footprint over 65MB for vector styles.";
diff --git a/test/util/merge_lines.test.cpp b/test/util/merge_lines.test.cpp
index 9a8f01ef35..8a3a400887 100644
--- a/test/util/merge_lines.test.cpp
+++ b/test/util/merge_lines.test.cpp
@@ -8,95 +8,131 @@ const std::u16string bbb = u"b";
using namespace mbgl;
-TEST(MergeLines, SameText) {
- // merges lines with the same text
- std::vector<mbgl::SymbolFeature> input1 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
- { FeatureType::LineString, {{{8, 0}, {9, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{5, 0}, {6, 0}}}, aaa, {}, 0 }
+class GeometryTileFeatureStub : public GeometryTileFeature {
+public:
+ GeometryTileFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
+ std::unordered_map<std::string, Value> properties_) :
+ id(id_),
+ type(type_),
+ geometry(geometry_),
+ properties(properties_)
+ {}
+
+ FeatureType getType() const override { return type; }
+ optional<Value> getValue(const std::string& key) const override {
+ auto it = properties.find(key);
+ if (it != properties.end()) {
+ return it->second;
+ }
+ return {};
};
+ std::unordered_map<std::string,Value> getProperties() const override { return properties; };
+ optional<FeatureIdentifier> getID() const override { return id; };
+ GeometryCollection getGeometries() const override { return geometry; };
+
+ optional<FeatureIdentifier> id;
+ FeatureType type;
+ GeometryCollection geometry;
+ std::unordered_map<std::string,Value> properties;
+};
+
+class SymbolFeatureStub : public SymbolFeature {
+public:
+ SymbolFeatureStub(optional<FeatureIdentifier> id_, FeatureType type_, GeometryCollection geometry_,
+ std::unordered_map<std::string, Value> properties_, optional<std::u16string> text_,
+ optional<std::string> icon_, std::size_t index_) :
+ SymbolFeature(std::make_unique<GeometryTileFeatureStub>(id_, type_, geometry_, properties_))
+ {
+ text = text_;
+ icon = icon_;
+ index = index_;
+ }
+};
- const std::vector<mbgl::SymbolFeature> expected1 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, bbb, {}, 0 },
- { FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 }
+TEST(MergeLines, SameText) {
+ // merges lines with the same text
+ std::vector<mbgl::SymbolFeature> input1;
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, bbb, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{8, 0}, {9, 0}}}, {}, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{6, 0}, {7, 0}, {8, 0}}}, {}, aaa, {}, 0));
+ input1.push_back(SymbolFeatureStub({}, FeatureType::LineString, {{{5, 0}, {6, 0}}}, {}, aaa, {}, 0));
+
+ const std::vector<GeometryTileFeatureStub> expected1 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}}}, {} },
+ { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {} },
+ { {}, FeatureType::LineString, {{{5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} }
};
-
+
mbgl::util::mergeLines(input1);
for (int i = 0; i < 6; i++) {
- EXPECT_TRUE(input1[i].geometry == expected1[i].geometry);
+ EXPECT_TRUE(input1[i].geometry == expected1[i].getGeometries());
}
}
TEST(MergeLines, BothEnds) {
// mergeLines handles merge from both ends
- std::vector<mbgl::SymbolFeature> input2 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 }
- };
-
- const std::vector<mbgl::SymbolFeature> expected2 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 }
+ std::vector<mbgl::SymbolFeature> input2;
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {5, 0}, {6, 0}}}, {}, aaa, {}, 0 });
+ input2.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
+
+ const std::vector<GeometryTileFeatureStub> expected2 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {6, 0}}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} }
};
mbgl::util::mergeLines(input2);
for (int i = 0; i < 3; i++) {
- EXPECT_TRUE(input2[i].geometry == expected2[i].geometry);
+ EXPECT_TRUE(input2[i].geometry == expected2[i].getGeometries());
}
}
TEST(MergeLines, CircularLines) {
// mergeLines handles circular lines
- std::vector<mbgl::SymbolFeature> input3 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{{4, 0}, {0, 0}}}, aaa, {}, 0 }
- };
-
- const std::vector<mbgl::SymbolFeature> expected3 = {
- { FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 },
- { FeatureType::LineString, {{}}, aaa, {}, 0 }
+ std::vector<mbgl::SymbolFeature> input3;
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}}}, {}, aaa, {}, 0 });
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{2, 0}, {3, 0}, {4, 0}}}, {}, aaa, {}, 0 });
+ input3.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{{4, 0}, {0, 0}}}, {}, aaa, {}, 0 });
+
+ const std::vector<GeometryTileFeatureStub> expected3 = {
+ { {}, FeatureType::LineString, {{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 0}}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} },
+ { {}, FeatureType::LineString, {{}}, {} }
};
mbgl::util::mergeLines(input3);
for (int i = 0; i < 3; i++) {
- EXPECT_TRUE(input3[i].geometry == expected3[i].geometry);
+ EXPECT_TRUE(input3[i].geometry == expected3[i].getGeometries());
}
}
TEST(MergeLines, EmptyOuterGeometry) {
- std::vector<mbgl::SymbolFeature> input = {
- { FeatureType::LineString, {}, aaa, {}, 0 },
- };
+ std::vector<mbgl::SymbolFeature> input;
+ input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {}, {}, aaa, {}, 0 });
- const std::vector<mbgl::SymbolFeature> expected = input;
+ const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {}, {} } };
mbgl::util::mergeLines(input);
- EXPECT_EQ(expected[0].geometry, input[0].geometry);
+ EXPECT_EQ(input[0].geometry, expected[0].getGeometries());
}
TEST(MergeLines, EmptyInnerGeometry) {
- std::vector<mbgl::SymbolFeature> input = {
- { FeatureType::LineString, {{}}, aaa, {}, 0 },
- };
+ std::vector<mbgl::SymbolFeature> input;
+ input.push_back(SymbolFeatureStub { {}, FeatureType::LineString, {{}}, {}, aaa, {}, 0 });
- const std::vector<mbgl::SymbolFeature> expected = input;
+ const std::vector<GeometryTileFeatureStub> expected = { { {}, FeatureType::LineString, {{}}, {} } };
mbgl::util::mergeLines(input);
- EXPECT_EQ(expected[0].geometry, input[0].geometry);
+ EXPECT_EQ(input[0].geometry, expected[0].getGeometries());
}
diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp
index 31fb985394..feaabf2630 100644
--- a/test/util/offscreen_texture.test.cpp
+++ b/test/util/offscreen_texture.test.cpp
@@ -4,6 +4,7 @@
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/headless_backend.hpp>
#include <mbgl/gl/offscreen_view.hpp>
+#include <mbgl/map/backend_scope.hpp>
#include <mbgl/util/offscreen_texture.hpp>
@@ -11,6 +12,7 @@ using namespace mbgl;
TEST(OffscreenTexture, EmptyRed) {
HeadlessBackend backend { test::sharedDisplay() };
+ BackendScope scope { backend };
OffscreenView view(backend.getContext(), { 512, 256 });
view.bind();
@@ -68,6 +70,7 @@ struct Buffer {
TEST(OffscreenTexture, RenderToTexture) {
HeadlessBackend backend { test::sharedDisplay() };
+ BackendScope scope { backend };
auto& context = backend.getContext();
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
@@ -116,50 +119,45 @@ void main() {
Buffer triangleBuffer({ 0, 0.5, 0.5, -0.5, -0.5, -0.5 });
Buffer viewportBuffer({ -1, -1, 1, -1, -1, 1, 1, 1 });
- // Make sure the texture gets destructed before we call context.reset();
- {
- OffscreenView view(context, { 512, 256 });
- view.bind();
-
- // First, draw red to the bound FBO.
- context.clear(Color::red(), {}, {});
-
- // Then, create a texture, bind it, and render yellow to that texture. This should not
- // affect the originally bound FBO.
- OffscreenTexture texture(context, { 128, 128 });
- texture.bind();
-
- context.clear(Color(), {}, {});
-
- MBGL_CHECK_ERROR(glUseProgram(paintShader.program));
- MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer));
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos));
- MBGL_CHECK_ERROR(
- glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3));
-
- auto image = texture.readStillImage();
- test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
-
- // Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
- view.bind();
-
- image = view.readStillImage();
- test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
-
- // Now, composite the Framebuffer texture we've rendered to onto the main FBO.
- context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear);
- MBGL_CHECK_ERROR(glUseProgram(compositeShader.program));
- MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
- MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));
- MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos));
- MBGL_CHECK_ERROR(
- glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
- MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
-
- image = view.readStillImage();
- test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1);
- }
+ OffscreenView view(context, { 512, 256 });
+ view.bind();
+
+ // First, draw red to the bound FBO.
+ context.clear(Color::red(), {}, {});
+
+ // Then, create a texture, bind it, and render yellow to that texture. This should not
+ // affect the originally bound FBO.
+ OffscreenTexture texture(context, { 128, 128 });
+ texture.bind();
+
+ context.clear(Color(), {}, {});
+
+ MBGL_CHECK_ERROR(glUseProgram(paintShader.program));
+ MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer));
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos));
+ MBGL_CHECK_ERROR(
+ glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
+ MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3));
+
+ auto image = texture.readStillImage();
+ test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
+
+ // Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
+ view.bind();
- context.reset();
+ image = view.readStillImage();
+ test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
+
+ // Now, composite the Framebuffer texture we've rendered to onto the main FBO.
+ context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear);
+ MBGL_CHECK_ERROR(glUseProgram(compositeShader.program));
+ MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
+ MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));
+ MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos));
+ MBGL_CHECK_ERROR(
+ glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
+ MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+
+ image = view.readStillImage();
+ test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1);
}
diff --git a/test/util/thread.test.cpp b/test/util/thread.test.cpp
index fc41fd4b78..972bddf383 100644
--- a/test/util/thread.test.cpp
+++ b/test/util/thread.test.cpp
@@ -3,6 +3,8 @@
#include <mbgl/test/util.hpp>
+#include <atomic>
+
using namespace mbgl::util;
class TestObject {
@@ -216,3 +218,79 @@ TEST(Thread, WorkRequestDeletionCancelsImmediately) {
started.get_future().get();
request1.reset();
}
+
+TEST(Thread, DeletePausedThread) {
+ RunLoop loop;
+
+ std::atomic_bool flag(false);
+
+ auto thread = std::make_unique<Thread<TestWorker>>(ThreadContext{"Test"});
+ thread->pause();
+ thread->invoke(&TestWorker::send, [&] { flag = true; }, [] {});
+
+ // Should not hang.
+ thread.reset();
+
+ // Should process the queue before destruction.
+ ASSERT_TRUE(flag);
+}
+
+TEST(Thread, Pause) {
+ RunLoop loop;
+
+ std::atomic_bool flag(false);
+
+ Thread<TestWorker> thread1({"Test1"});
+ thread1.pause();
+
+ Thread<TestWorker> thread2({"Test2"});
+
+ for (unsigned i = 0; i < 100; ++i) {
+ thread1.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
+ thread2.invoke(&TestWorker::send, [&] { ASSERT_FALSE(flag); }, [] {});
+ }
+
+ // Queue a message at the end of thread2 queue.
+ thread2.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+ loop.run();
+}
+
+TEST(Thread, Resume) {
+ RunLoop loop;
+
+ std::atomic_bool flag(false);
+
+ Thread<TestWorker> thread({"Test"});
+ thread.pause();
+
+ for (unsigned i = 0; i < 100; ++i) {
+ thread.invoke(&TestWorker::send, [&] { flag = true; }, [] {});
+ }
+
+ // Thread messages are ondered, when we resume, this is going
+ // to me the last thing to run on the message queue.
+ thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+
+ // This test will be flaky if the thread doesn't get paused.
+ ASSERT_FALSE(flag);
+
+ thread.resume();
+ loop.run();
+
+ ASSERT_TRUE(flag);
+}
+
+TEST(Thread, PauseResume) {
+ RunLoop loop;
+
+ Thread<TestWorker> thread({"Test"});
+
+ // Test if multiple pause/resume work.
+ for (unsigned i = 0; i < 100; ++i) {
+ thread.pause();
+ thread.resume();
+ }
+
+ thread.invoke(&TestWorker::send, [&] { loop.stop(); }, [] {});
+ loop.run();
+}
diff --git a/test/util/url.test.cpp b/test/util/url.test.cpp
index 2acf3cb0db..ca24a5949a 100644
--- a/test/util/url.test.cpp
+++ b/test/util/url.test.cpp
@@ -26,6 +26,9 @@ TEST(URL, isURL) {
TEST(URL, Scheme) {
EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://example.com/test?query=foo").scheme);
+ EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://127.0.0.1:8080/test?query=foo").scheme);
+ EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").scheme);
+ EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http://user:password@example.com.:80/test?query=foo").scheme);
EXPECT_EQ(URL::Segment({ 0, 0 }), URL("htt").scheme);
EXPECT_EQ(URL::Segment({ 0, 6 }), URL("mapbox://").scheme);
EXPECT_EQ(URL::Segment({ 0, 6 }), URL("mapbox:/#").scheme);
@@ -33,12 +36,17 @@ TEST(URL, Scheme) {
EXPECT_EQ(URL::Segment({ 0, 0 }), URL("").scheme);
EXPECT_EQ(URL::Segment({ 0, 0 }), URL("http?query://baz").scheme);
EXPECT_EQ(URL::Segment({ 0, 0 }), URL(":::").scheme);
+ EXPECT_EQ(URL::Segment({ 0, 0 }), URL("127.0.0.1:8080/test?query=foo").scheme);
+ EXPECT_EQ(URL::Segment({ 0, 0 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").scheme);
EXPECT_EQ(URL::Segment({ 0, 4 }), URL("data:,Hello%2C%20World!").scheme);
EXPECT_EQ(URL::Segment({ 0, 4 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").scheme);
}
TEST(URL, Query) {
EXPECT_EQ(URL::Segment({ 23, 10 }), URL("http://example.com/test?query=foo").query);
+ EXPECT_EQ(URL::Segment({ 26, 10 }), URL("http://127.0.0.1:8080/test?query=foo").query);
+ EXPECT_EQ(URL::Segment({ 47, 10 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").query);
+ EXPECT_EQ(URL::Segment({ 41, 10 }), URL("http://user:password@example.com.:80/test?query=foo").query);
EXPECT_EQ(URL::Segment({ 23, 10 }), URL("http://example.com/test?query=foo#page-2").query);
EXPECT_EQ(URL::Segment({ 23, 0 }), URL("http://example.com/test#query=foo?page-2").query);
EXPECT_EQ(URL::Segment({ 0, 10 }), URL("?query=foo").query);
@@ -49,12 +57,17 @@ TEST(URL, Query) {
EXPECT_EQ(URL::Segment({ 12, 0 }), URL("mapbox://bar").query);
EXPECT_EQ(URL::Segment({ 0, 0 }), URL("").query);
EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").query);
+ EXPECT_EQ(URL::Segment({ 19, 10 }), URL("127.0.0.1:8080/test?query=foo").query);
+ EXPECT_EQ(URL::Segment({ 40, 10 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").query);
EXPECT_EQ(URL::Segment({ 23, 0 }), URL("data:,Hello%2C%20World!").query);
EXPECT_EQ(URL::Segment({ 47, 0 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").query);
}
TEST(URL, Domain) {
EXPECT_EQ(URL::Segment({ 7, 11 }), URL("http://example.com/test?query=foo").domain);
+ EXPECT_EQ(URL::Segment({ 7, 14 }), URL("http://127.0.0.1:8080/test?query=foo").domain);
+ EXPECT_EQ(URL::Segment({ 7, 35 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").domain);
+ EXPECT_EQ(URL::Segment({ 7, 29 }), URL("http://user:password@example.com.:80/test?query=foo").domain);
EXPECT_EQ(URL::Segment({ 5, 11 }), URL("http:example.com/test?query=foo").domain);
EXPECT_EQ(URL::Segment({ 0, 3 }), URL("htt").domain);
EXPECT_EQ(URL::Segment({ 0, 4 }), URL("http?query://baz").domain);
@@ -71,18 +84,25 @@ TEST(URL, Domain) {
EXPECT_EQ(URL::Segment({ 7, 6 }), URL("http://domain?").domain);
EXPECT_EQ(URL::Segment({ 7, 6 }), URL("http://domain?foo").domain);
EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").domain);
+ EXPECT_EQ(URL::Segment({ 0, 14 }), URL("127.0.0.1:8080/test?query=foo").domain);
+ EXPECT_EQ(URL::Segment({ 0, 35 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").domain);
EXPECT_EQ(URL::Segment({ 5, 0 }), URL("data:,Hello%2C%20World!").domain);
EXPECT_EQ(URL::Segment({ 5, 17 }), URL("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D").domain);
}
TEST(URL, Path) {
EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test?query=foo").path);
+ EXPECT_EQ(URL::Segment({ 21, 5 }), URL("http://127.0.0.1:8080/test?query=foo").path);
+ EXPECT_EQ(URL::Segment({ 42, 5 }), URL("http://[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").path);
+ EXPECT_EQ(URL::Segment({ 36, 5 }), URL("http://user:password@example.com.:80/test?query=foo").path);
EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test?query=foo#bar").path);
EXPECT_EQ(URL::Segment({ 18, 5 }), URL("http://example.com/test#bar").path);
EXPECT_EQ(URL::Segment({ 18, 0 }), URL("http://example.com?query=foo").path);
EXPECT_EQ(URL::Segment({ 18, 0 }), URL("http://example.com#?query=foo").path);
EXPECT_EQ(URL::Segment({ 18, 1 }), URL("http://example.com/?query=foo").path);
EXPECT_EQ(URL::Segment({ 3, 0 }), URL(":::").path);
+ EXPECT_EQ(URL::Segment({ 14, 5 }), URL("127.0.0.1:8080/test?query=foo").path);
+ EXPECT_EQ(URL::Segment({ 35, 5 }), URL("[2a01:4f8:c17:3680::386a:6f3d]:8080/test?query=foo").path);
EXPECT_EQ(URL::Segment({ 13, 0 }), URL("http://domain").path);
EXPECT_EQ(URL::Segment({ 6, 4 }), URL("domain/foo?bar").path);
EXPECT_EQ(URL::Segment({ 6, 17 }), URL("data:,Hello%2C%20World!").path);