diff options
author | Tim Watson <tewatson89@gmail.com> | 2019-04-03 14:51:13 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-03 14:51:13 -0700 |
commit | 0ff25060dae4858a1b60e2277dbd8921de7a6785 (patch) | |
tree | d29d578b9b9d6cfb0999b7a30819d379b85172b7 | |
parent | ba2b7a74c420856401d344ff15b27771175c9819 (diff) | |
parent | 0f416fbbde9b146eb28a4bf88586738d12505007 (diff) | |
download | qtlocation-mapboxgl-upstream/friedbunny-external-pr-14135.tar.gz |
Merge pull request #1 from mapbox/masterupstream/friedbunny-external-pr-14135
Merge Master
402 files changed, 13395 insertions, 4601 deletions
diff --git a/.gitmodules b/.gitmodules index a36fee4c0e..aeb2663b84 100644 --- a/.gitmodules +++ b/.gitmodules @@ -91,3 +91,6 @@ [submodule "platform/darwin/docs/theme"] path = platform/darwin/docs/theme url = https://github.com/mapbox/jazzy-theme.git +[submodule "vendor/args"] + path = vendor/args + url = https://github.com/Taywee/args @@ -1,5 +1,8 @@ export BUILDTYPE ?= Debug +export IS_LOCAL_DEVELOPMENT ?= true export WITH_CXX11ABI ?= $(shell scripts/check-cxx11abi.sh) +export TARGET_BRANCH ?= master + ifeq ($(BUILDTYPE), Release) else ifeq ($(BUILDTYPE), RelWithDebInfo) @@ -55,6 +58,8 @@ default: test BUILD_DEPS += Makefile BUILD_DEPS += CMakeLists.txt +BUILD_DOCS ?= true + #### macOS targets ############################################################## ifeq ($(HOST_PLATFORM), macos) @@ -92,7 +97,7 @@ macos: $(MACOS_PROJ_PATH) .PHONY: xproj xproj: $(MACOS_PROJ_PATH) - open $(MACOS_WORK_PATH) + xed $(MACOS_WORK_PATH) .PHONY: test test: $(MACOS_PROJ_PATH) @@ -188,12 +193,11 @@ compdb: $(BUILD_DEPS) $(TEST_DEPS) $(MACOS_COMPDB_PATH)/Makefile .PHONY: tidy tidy: compdb - scripts/clang-tools.sh $(MACOS_COMPDB_PATH) + scripts/clang-tools.sh $(MACOS_COMPDB_PATH) $(TARGET_BRANCH) .PHONY: check check: compdb - scripts/clang-tools.sh $(MACOS_COMPDB_PATH) --diff - + scripts/clang-tools.sh $(MACOS_COMPDB_PATH) $(TARGET_BRANCH) --diff endif #### iOS targets ############################################################## @@ -234,7 +238,7 @@ ios: $(IOS_PROJ_PATH) .PHONY: iproj iproj: $(IOS_PROJ_PATH) - open $(IOS_WORK_PATH) + xed $(IOS_WORK_PATH) .PHONY: ios-lint ios-lint: @@ -272,7 +276,7 @@ ipackage%: .PHONY: iframework iframework: $(IOS_PROJ_PATH) - FORMAT=$(FORMAT) BUILD_DEVICE=$(BUILD_DEVICE) SYMBOLS=$(SYMBOLS) \ + FORMAT=$(FORMAT) BUILD_DEVICE=$(BUILD_DEVICE) SYMBOLS=$(SYMBOLS) BUILD_DOCS=$(BUILD_DOCS) \ ./platform/ios/scripts/package.sh .PHONY: ideploy @@ -380,11 +384,11 @@ compdb: $(LINUX_BUILD) .PHONY: tidy tidy: compdb - scripts/clang-tools.sh $(LINUX_OUTPUT_PATH) + scripts/clang-tools.sh $(LINUX_OUTPUT_PATH) $(TARGET_BRANCH) .PHONY: check check: compdb - scripts/clang-tools.sh $(LINUX_OUTPUT_PATH) --diff + scripts/clang-tools.sh $(LINUX_OUTPUT_PATH) $(TARGET_BRANCH) --diff endif @@ -691,6 +695,16 @@ run-android-unit-test: platform/android/gradle/configuration.gradle run-android-unit-test-%: platform/android/gradle/configuration.gradle cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest --info --tests "$*" +# Run unit test and build a coverage report from .exec file generated by unit tests and .ec file generated by instrumentation tests +.PHONY: android-create-jacoco-report +android-create-jacoco-report: platform/android/gradle/configuration.gradle + cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:jacocoTestReport + +# Parse merged jacoco report and send it to S3 +.PHONY: android-parse-and-send-jacoco-report +android-parse-and-send-jacoco-report: + python platform/android/scripts/parse-jacoco-report.py + # Builds a release package of the Android SDK .PHONY: apackage apackage: platform/android/gradle/configuration.gradle diff --git a/benchmark/api/query.benchmark.cpp b/benchmark/api/query.benchmark.cpp index 47eba7a9fe..9b7c2d7273 100644 --- a/benchmark/api/query.benchmark.cpp +++ b/benchmark/api/query.benchmark.cpp @@ -7,7 +7,6 @@ #include <mbgl/renderer/renderer.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/network_status.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/io.hpp> @@ -21,7 +20,6 @@ class QueryBenchmark { public: QueryBenchmark() { NetworkStatus::Set(NetworkStatus::Status::Offline); - fileSource.setAccessToken("foobar"); map.getStyle().loadJSON(util::read_file("benchmark/fixtures/api/style.json")); map.jumpTo(CameraOptions().withCenter(LatLng { 40.726989, -73.992857 }).withZoom(15.0)); // Manhattan @@ -32,11 +30,11 @@ public: } util::RunLoop loop; - DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." }; ThreadPool threadPool{ 4 }; HeadlessFrontend frontend { { 1000, 1000 }, 1, threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, - fileSource, threadPool, MapOptions().withMapMode(MapMode::Static) }; + Map map { frontend, MapObserver::nullObserver(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()), + ResourceOptions().withCachePath("benchmark/fixtures/api/cache.db").withAssetPath(".").withAccessToken("foobar") }; ScreenBox box{{ 0, 0 }, { 1000, 1000 }}; }; diff --git a/benchmark/api/render.benchmark.cpp b/benchmark/api/render.benchmark.cpp index 9a91e8b3bc..3cff0d9056 100644 --- a/benchmark/api/render.benchmark.cpp +++ b/benchmark/api/render.benchmark.cpp @@ -8,7 +8,7 @@ #include <mbgl/renderer/renderer.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> -#include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/network_status.hpp> #include <mbgl/util/image.hpp> #include <mbgl/util/io.hpp> @@ -18,32 +18,36 @@ using namespace mbgl; namespace { +static std::string cachePath { "benchmark/fixtures/api/cache.db" }; +constexpr double pixelRatio { 1.0 }; +constexpr Size size { 1000, 1000 }; + class RenderBenchmark { public: RenderBenchmark() { NetworkStatus::Set(NetworkStatus::Status::Offline); - fileSource.setAccessToken("foobar"); } util::RunLoop loop; - DefaultFileSource fileSource { "benchmark/fixtures/api/cache.db", "." }; ThreadPool threadPool { 4 }; }; - + static void prepare(Map& map, optional<std::string> json = {}) { map.getStyle().loadJSON(json ? *json : util::read_file("benchmark/fixtures/api/style.json")); map.jumpTo(CameraOptions().withCenter(LatLng { 40.726989, -73.992857 }).withZoom(15.0)); // Manhattan - map.getStyle().addImage(std::make_unique<style::Image>("test-icon", - decodeImage(util::read_file("benchmark/fixtures/api/default_marker.png")), 1.0)); + + auto image = decodeImage(util::read_file("benchmark/fixtures/api/default_marker.png")); + map.getStyle().addImage(std::make_unique<style::Image>("test-icon", std::move(image), 1.0)); } - + } // end namespace static void API_renderStill_reuse_map(::benchmark::State& state) { RenderBenchmark bench; - HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, - bench.fileSource, bench.threadPool, MapOptions().withMapMode(MapMode::Static) }; + HeadlessFrontend frontend { size, pixelRatio, bench.threadPool }; + Map map { frontend, MapObserver::nullObserver(), bench.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") }; prepare(map); while (state.KeepRunning()) { @@ -53,9 +57,10 @@ static void API_renderStill_reuse_map(::benchmark::State& state) { static void API_renderStill_reuse_map_formatted_labels(::benchmark::State& state) { RenderBenchmark bench; - HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, - bench.fileSource, bench.threadPool, MapOptions().withMapMode(MapMode::Static) }; + HeadlessFrontend frontend { size, pixelRatio, bench.threadPool }; + Map map { frontend, MapObserver::nullObserver(), bench.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") }; prepare(map, util::read_file("benchmark/fixtures/api/style_formatted_labels.json")); while (state.KeepRunning()) { @@ -65,10 +70,11 @@ static void API_renderStill_reuse_map_formatted_labels(::benchmark::State& state static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) { RenderBenchmark bench; - HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, - bench.fileSource, bench.threadPool, MapOptions().withMapMode(MapMode::Static) }; - + HeadlessFrontend frontend { size, pixelRatio, bench.threadPool }; + Map map { frontend, MapObserver::nullObserver(), bench.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") }; + while (state.KeepRunning()) { prepare(map, { "{}" }); frontend.render(map); @@ -79,11 +85,12 @@ static void API_renderStill_reuse_map_switch_styles(::benchmark::State& state) { static void API_renderStill_recreate_map(::benchmark::State& state) { RenderBenchmark bench; - + while (state.KeepRunning()) { - HeadlessFrontend frontend { { 1000, 1000 }, 1, bench.threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), 1, - bench.fileSource, bench.threadPool, MapOptions().withMapMode(MapMode::Static) }; + HeadlessFrontend frontend { size, pixelRatio, bench.threadPool }; + Map map { frontend, MapObserver::nullObserver(), bench.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cachePath).withAccessToken("foobar") }; prepare(map); frontend.render(map); } diff --git a/bin/offline.cpp b/bin/offline.cpp index e5ce1f75fe..5cd43adfe3 100644 --- a/bin/offline.cpp +++ b/bin/offline.cpp @@ -5,7 +5,7 @@ #include <mbgl/storage/default_file_source.hpp> -#include <args/args.hxx> +#include <args.hxx> #include <cstdlib> #include <iostream> diff --git a/bin/render.cpp b/bin/render.cpp index 87a1e670b9..a805953693 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -6,10 +6,9 @@ #include <mbgl/gl/headless_frontend.hpp> #include <mbgl/util/default_thread_pool.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/style/style.hpp> -#include <args/args.hxx> +#include <args.hxx> #include <cstdlib> #include <iostream> @@ -76,17 +75,12 @@ int main(int argc, char *argv[]) { using namespace mbgl; util::RunLoop loop; - DefaultFileSource fileSource(cache_file, asset_root); - - // Set access token if present - if (token.size()) { - fileSource.setAccessToken(std::string(token)); - } ThreadPool threadPool(4); HeadlessFrontend frontend({ width, height }, pixelRatio, threadPool); - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, - fileSource, threadPool, MapOptions().withMapMode(MapMode::Static)); + Map map(frontend, MapObserver::nullObserver(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cache_file).withAssetPath(asset_root).withAccessToken(std::string(token))); if (style.find("://") == std::string::npos) { style = std::string("file://") + style; diff --git a/ci.template b/ci.template index f29d8d1608..578ce24c81 100644 --- a/ci.template +++ b/ci.template @@ -1,4 +1,3 @@ - { "AWSTemplateFormatVersion": "2010-09-09", "Description": "mapbox-gl-native travis resources", @@ -85,35 +84,6 @@ } }, { - "PolicyName": "android", - "PolicyDocument": { - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "ec2:DescribeInstances", - "ec2:RunInstances", - "ec2:CreateTags", - "ec2:GetConsoleOutput" - ], - "Resource": [ - "*" - ] - }, - { - "Effect": "Allow", - "Action": "iam:PassRole", - "Resource": { - "Fn::GetAtt": [ - "AndroidRole", - "Arn" - ] - } - } - ] - } - }, - { "PolicyName": "cloudwatch-metrics", "PolicyDocument": { "Statement": [ @@ -161,7 +131,9 @@ "Resource": [ "arn:aws:s3:::mapbox-loading-dock/raw/mobile.binarysize/*", "arn:aws:s3:::mapbox-loading-dock/raw/mobile.codecoverage/*", - "arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.docs_coverage/*" + "arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.docs_coverage/*", + "arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.codecoverage/*", + "arn:aws:s3:::mapbox-loading-dock/raw/mobile_staging.github_stats/*" ] } ] @@ -231,72 +203,6 @@ "Ref": "BuildUser" } } - }, - "AndroidRole": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Effect": "Allow", - "Principal": { - "Service": [ - "ec2.amazonaws.com" - ] - }, - "Action": [ - "sts:AssumeRole" - ] - } - ] - }, - "Policies": [ - { - "PolicyName": "android-testing", - "PolicyDocument": { - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "s3:PutObject" - ], - "Resource": [ - "arn:aws:s3:::mapbox-gl-testing/android/*" - ] - } - ] - } - }, - { - "PolicyName": "android", - "PolicyDocument": { - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "s3:PutObject" - ], - "Resource": [ - "arn:aws:s3:::mapbox/mapbox-gl-native/android/build/*" - ] - } - ] - } - } - ], - "Path": "/android-gl-build/travis/role/" - } - }, - "AndroidInstanceProfile": { - "Type": "AWS::IAM::InstanceProfile", - "Properties": { - "Roles": [ - { - "Ref": "AndroidRole" - } - ], - "Path": "/android-gl-build/travis/instance-profile/" - } } }, "Outputs": { @@ -312,22 +218,6 @@ "SecretAccessKey" ] } - }, - "AndroidInstanceProfile": { - "Value": { - "Fn::GetAtt": [ - "AndroidInstanceProfile", - "Arn" - ] - } - }, - "AndroidRole": { - "Value": { - "Fn::GetAtt": [ - "AndroidRole", - "Arn" - ] - } } } } diff --git a/circle.yml b/circle.yml index 6883cd6f5a..21f3c023ca 100644 --- a/circle.yml +++ b/circle.yml @@ -15,8 +15,8 @@ workflows: - android-arm-template: name: android-gnustl-arm-v7 stl: gnustl_shared - firebase_device_id: "m0" - firebase_device_os: "18" + firebase_device_id: "htc_m8" + firebase_device_os: "19" image: android-ndk-r17c:1d5db0eb34 abi: arm-v7 - android-release: @@ -44,6 +44,8 @@ workflows: - linux-gcc5-debug-coverage - linux-doxygen - ios-debug + - ios-debug-xcode-102: + name: ios-debug-xcode-10.2 - ios-release-template: name: ios-release - ios-release-tag: @@ -64,6 +66,7 @@ workflows: only: - master jobs: + - metrics-nightly - ios-release-template: name: ios-release-nightly - ios-sanitize-nightly @@ -500,7 +503,7 @@ jobs: command: make compdb - run: name: Run Clang checks - command: make check + command: make check TARGET_BRANCH=${CIRCLE_TARGET_BRANCH:master} no_output_timeout: 20m - save-dependencies: { ccache: false } @@ -571,7 +574,16 @@ jobs: gcloud firebase test android run --type instrumentation \ --app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/debug/MapboxGLAndroidSDKTestApp-debug.apk \ --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/androidTest/debug/MapboxGLAndroidSDKTestApp-debug-androidTest.apk \ - --device-ids << parameters.firebase_device_id >> --os-version-ids << parameters.firebase_device_os >> --locales en --orientations portrait --timeout 20m + --device-ids << parameters.firebase_device_id >> --os-version-ids << parameters.firebase_device_os >> --locales en --orientations portrait --timeout 20m \ + --environment-variables coverage=true,coverageFile="/sdcard/coverage.ec" --directories-to-pull /sdcard --results-dir mapbox-android-sdk-${CIRCLE_BUILD_NUM} + coverageFile=`gsutil ls gs://test-lab-186672a0qp5bq-ycr70axads3nc/mapbox-android-sdk-${CIRCLE_BUILD_NUM}/**/*.ec | tail -1` + gsutil cp $coverageFile $PWD/platform/android/MapboxGLAndroidSDK/build/jacoco | true + fi + - run: + name: Parse and send Jacoco reports + command: | + if [[ $CIRCLE_BRANCH == master ]]; then + make android-create-jacoco-report && make android-parse-and-send-jacoco-report fi - store_artifacts: path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/debug @@ -838,6 +850,9 @@ jobs: - build-test - save-dependencies - run-unit-tests + - run: + name: Build offline CLI + command: make offline # ------------------------------------------------------------------------------ linux-gcc5-debug-coverage: @@ -864,6 +879,12 @@ jobs: curl -sSfL -o codecov https://codecov.io/bash chmod +x codecov ./codecov -c + - run: + name: Upload coverage metrics to s3 + command: | + if [[ $CIRCLE_BRANCH == master ]]; then + scripts/publish_core_codecoverage.js -p Linux -s Core + fi # ------------------------------------------------------------------------------ linux-doxygen: @@ -916,6 +937,46 @@ jobs: - upload-xcode-build-logs # ------------------------------------------------------------------------------ + ios-debug-xcode-102: + macos: + xcode: "10.2.0" + environment: + BUILDTYPE: Debug + HOMEBREW_NO_AUTO_UPDATE: 1 + steps: + - install-macos-dependencies + - install-dependencies + - build-ios-test + - check-public-symbols + - run: + name: Check symbol namespacing for mapbox-events-ios + command: make ios-check-events-symbols + - run: + name: Lint plist files + command: make ios-lint + - run: + name: Nitpick Darwin code generation + command: scripts/nitpick/generated-code.js darwin + - save-dependencies + - collect-xcode-build-logs + - upload-xcode-build-logs + +# ------------------------------------------------------------------------------ + metrics-nightly: + docker: + - image: mbgl/linux-gcc-5:54f59e3ac5 + working_directory: /src + environment: + LIBSYSCONFCPUS: 2 + JOBS: 2 + steps: + - install-dependencies + - run: + name: Collect GitHub statistics + command: | + scripts/publish_github_stats.js + +# ------------------------------------------------------------------------------ ios-sanitize-nightly: macos: xcode: "10.1.0" diff --git a/cmake/glfw.cmake b/cmake/glfw.cmake index a2adb9fbb5..4ef6890cef 100644 --- a/cmake/glfw.cmake +++ b/cmake/glfw.cmake @@ -2,9 +2,6 @@ add_executable(mbgl-glfw platform/glfw/main.cpp ) -# args requires RTTI -set_source_files_properties(platform/glfw/main.cpp PROPERTIES COMPILE_OPTIONS "-frtti") - target_sources(mbgl-glfw PRIVATE platform/glfw/glfw_view.hpp PRIVATE platform/glfw/glfw_view.cpp @@ -23,10 +20,9 @@ target_link_libraries(mbgl-glfw PRIVATE mbgl-core PRIVATE glfw PRIVATE cheap-ruler-cpp + PRIVATE args ) -target_add_mason_package(mbgl-glfw PRIVATE args) - mbgl_platform_glfw() create_source_groups(mbgl-glfw) diff --git a/cmake/loop-darwin.cmake b/cmake/loop-darwin.cmake index a330375653..46d8f9edc0 100644 --- a/cmake/loop-darwin.cmake +++ b/cmake/loop-darwin.cmake @@ -7,6 +7,10 @@ target_include_directories(mbgl-loop-darwin PRIVATE src ) +target_link_libraries(mbgl-loop-darwin PUBLIC + optional +) + create_source_groups(mbgl-loop-darwin) set_target_properties(mbgl-loop-darwin PROPERTIES FOLDER "Core") diff --git a/cmake/mason-dependencies.cmake b/cmake/mason-dependencies.cmake index 71a94f096f..a6ef7a3a53 100644 --- a/cmake/mason-dependencies.cmake +++ b/cmake/mason-dependencies.cmake @@ -8,14 +8,11 @@ elseif(MBGL_PLATFORM STREQUAL "linux") mason_use(libuv VERSION 1.9.1) mason_use(libpng VERSION 1.6.25) mason_use(libjpeg-turbo VERSION 1.5.0) - mason_use(args VERSION 6.2.0 HEADER_ONLY) if(WITH_EGL) mason_use(swiftshader VERSION 2018-05-31) endif() elseif(MBGL_PLATFORM STREQUAL "macos") - mason_use(args VERSION 6.2.0 HEADER_ONLY) - if(WITH_EGL) mason_use(swiftshader VERSION 2018-05-31) endif() diff --git a/cmake/offline.cmake b/cmake/offline.cmake index b751125297..3fa075f07b 100644 --- a/cmake/offline.cmake +++ b/cmake/offline.cmake @@ -2,9 +2,6 @@ add_executable(mbgl-offline bin/offline.cpp ) -# args requires RTTI -set_source_files_properties(bin/offline.cpp PROPERTIES COMPILE_OPTIONS "-frtti") - target_sources(mbgl-offline PRIVATE platform/default/include/mbgl/util/default_styles.hpp ) @@ -15,10 +12,9 @@ target_include_directories(mbgl-offline target_link_libraries(mbgl-offline PRIVATE mbgl-core + PRIVATE args ) -target_add_mason_package(mbgl-offline PRIVATE args) - mbgl_platform_offline() create_source_groups(mbgl-offline) diff --git a/cmake/render.cmake b/cmake/render.cmake index 776c859bad..a625b3f21f 100644 --- a/cmake/render.cmake +++ b/cmake/render.cmake @@ -2,19 +2,15 @@ add_executable(mbgl-render bin/render.cpp ) -# args requires RTTI -set_source_files_properties(bin/render.cpp PROPERTIES COMPILE_OPTIONS "-frtti") - target_include_directories(mbgl-render PRIVATE platform/default/include ) target_link_libraries(mbgl-render PRIVATE mbgl-core + PRIVATE args ) -target_add_mason_package(mbgl-render PRIVATE args) - mbgl_platform_render() create_source_groups(mbgl-render) diff --git a/cmake/vendor.cmake b/cmake/vendor.cmake index ddeefad76d..7aac53e4cb 100644 --- a/cmake/vendor.cmake +++ b/cmake/vendor.cmake @@ -29,5 +29,6 @@ include(${CMAKE_SOURCE_DIR}/vendor/vector-tile.cmake) include(${CMAKE_SOURCE_DIR}/vendor/wagyu.cmake) if(MBGL_PLATFORM STREQUAL "linux" OR MBGL_PLATFORM STREQUAL "macos") + include(${CMAKE_SOURCE_DIR}/vendor/args.cmake) include(${CMAKE_SOURCE_DIR}/vendor/glfw.cmake) endif() diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index b4f60a19ba..2fdd72dcb8 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -12,6 +12,7 @@ #include <mbgl/map/camera.hpp> #include <mbgl/util/geometry.hpp> #include <mbgl/map/projection_mode.hpp> +#include <mbgl/storage/resource_options.hpp> #include <cstdint> #include <string> @@ -21,7 +22,6 @@ namespace mbgl { -class FileSource; class Scheduler; class RendererFrontend; @@ -34,11 +34,9 @@ class Map : private util::noncopyable { public: explicit Map(RendererFrontend&, MapObserver&, - Size size, - float pixelRatio, - FileSource&, Scheduler&, - const MapOptions&); + const MapOptions&, + const ResourceOptions&); ~Map(); // Register a callback that will get called (on the render thread) when all resources have @@ -87,26 +85,17 @@ public: /// @} - // North Orientation + // Map Options void setNorthOrientation(NorthOrientation); - NorthOrientation getNorthOrientation() const; - - // Constrain mode void setConstrainMode(ConstrainMode); - ConstrainMode getConstrainMode() const; - - // Viewport mode void setViewportMode(ViewportMode); - ViewportMode getViewportMode() const; + void setSize(Size); + MapOptions getMapOptions() const; //Projection Mode void setProjectionMode(const ProjectionMode&); ProjectionMode getProjectionMode() const; - // Size - void setSize(Size); - Size getSize() const; - // Projection ScreenCoordinate pixelForLatLng(const LatLng&) const; LatLng latLngForPixel(const ScreenCoordinate&) const; @@ -137,9 +126,12 @@ public: bool isFullyLoaded() const; void dumpDebugLogs() const; -private: +protected: class Impl; const std::unique_ptr<Impl> impl; + + // For testing only. + Map(std::unique_ptr<Impl>); }; } // namespace mbgl diff --git a/include/mbgl/map/map_observer.hpp b/include/mbgl/map/map_observer.hpp index 8ad9e93d0b..75e389df9f 100644 --- a/include/mbgl/map/map_observer.hpp +++ b/include/mbgl/map/map_observer.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/style/source.hpp> +#include <mbgl/style/image.hpp> #include <cstdint> #include <string> @@ -46,6 +47,7 @@ public: virtual void onDidFinishLoadingStyle() {} virtual void onSourceChanged(style::Source&) {} virtual void onDidBecomeIdle() {} + virtual void onStyleImageMissing(const std::string&) {} }; } // namespace mbgl diff --git a/include/mbgl/map/map_options.hpp b/include/mbgl/map/map_options.hpp index 13772332a8..fcb8c8f32f 100644 --- a/include/mbgl/map/map_options.hpp +++ b/include/mbgl/map/map_options.hpp @@ -1,16 +1,17 @@ #pragma once #include <mbgl/map/mode.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/size.hpp> #include <memory> -#include <string> namespace mbgl { /** * @brief Holds values for Map options. */ -class MapOptions { +class MapOptions final { public: /** * @brief Constructs a MapOptions object with default values. @@ -18,13 +19,15 @@ public: MapOptions(); ~MapOptions(); + MapOptions(MapOptions&&) noexcept; + /** * @brief Sets the map rendering mode. By default, it is set to Continuous * so the map will render as data arrives from the network and react * immediately to state changes. * * @param mode Map rendering mode. - * @return reference to MapOptions for chaining options together. + * @return MapOptions for chaining options together. */ MapOptions& withMapMode(MapMode mode); @@ -41,7 +44,7 @@ public: * HeightOnly. * * @param mode Map constrain mode. - * @return reference to MapOptions for chaining options together. + * @return MapOptions for chaining options together. */ MapOptions& withConstrainMode(ConstrainMode mode); @@ -57,7 +60,7 @@ public: * orientation of the map as some devices may use inverted orientation. * * @param mode Viewport mode. - * @return reference to MapOptions for chaining options together. + * @return MapOptions for chaining options together. */ MapOptions& withViewportMode(ViewportMode mode); @@ -69,71 +72,71 @@ public: ViewportMode viewportMode() const; /** - * @brief Sets the cache path. + * @brief Specify whether to enable cross-source symbol collision detection + * or not. By default, it is set to true. * - * @param path Cache path. - * @return reference to MapOptions for chaining options together. + * @param enableCollisions true to enable, false to disable + * @return MapOptions for chaining options together. */ - MapOptions& withCachePath(std::string path); + MapOptions& withCrossSourceCollisions(bool enableCollisions); /** - * @brief Gets the previously set (or default) cache path. + * @brief Gets the previously set (or default) crossSourceCollisions value. * - * @return cache path + * @return true if ecross-source symbol collision detection enabled, + * false otherwise. */ - const std::string& cachePath() const; + bool crossSourceCollisions() const; /** - * @brief Sets the asset path, which is the root directory from where - * the asset:// scheme gets resolved in a style. + * @brief Sets the orientation of the Map. By default, it is set to + * Upwards. * - * @param path Asset path. + * @param orientation Orientation of the Map. * @return reference to MapOptions for chaining options together. */ - MapOptions& withAssetRoot(std::string path); + MapOptions& withNorthOrientation(NorthOrientation orientation); /** - * @brief Gets the previously set (or default) asset path. + * @brief Gets the previously set (or default) orientation. * - * @return asset path + * @return Map orientation. */ - const std::string& assetRoot() const; + NorthOrientation northOrientation() const; /** - * @brief Sets the maximum cache size. + * @brief Sets the size to resize the map object and renderer backend. * - * @param size Cache maximum size in bytes. + * @param size_ A size given in logical pixels. * @return reference to MapOptions for chaining options together. */ - MapOptions& withMaximumCacheSize(uint64_t size); + MapOptions& withSize(Size size_); /** - * @brief Gets the previously set (or default) maximum allowed cache size. + * @brief Gets the previously set size. * - * @return maximum allowed cache database size in bytes. + * @return Size. */ - uint64_t maximumCacheSize() const; + Size size() const; /** - * @brief Specify whether to enable cross-source symbol collision detection - * or not. By default, it is set to true. + * @brief Sets the custom pixel ratio. By default, it is set to 1. * - * @param enableCollisions true to enable, false to disable + * @param ratio Pixel ratio value. * @return reference to MapOptions for chaining options together. */ - MapOptions& withCrossSourceCollisions(bool enableCollisions); + MapOptions& withPixelRatio(float ratio); /** - * @brief Gets the previously set (or default) crossSourceCollisions value. + * @brief Gets the previously set (or default) pixel ratio value. * - * @return true if ecross-source symbol collision detection enabled, - * false otherwise. + * @return pixel ratio value. */ - bool crossSourceCollisions() const; + float pixelRatio() const; private: class Impl; - std::shared_ptr<Impl> impl_; + std::unique_ptr<Impl> impl_; }; } // namespace mbgl diff --git a/include/mbgl/renderer/renderer.hpp b/include/mbgl/renderer/renderer.hpp index 1d92f9c0cb..0bed4cdaa8 100644 --- a/include/mbgl/renderer/renderer.hpp +++ b/include/mbgl/renderer/renderer.hpp @@ -34,6 +34,8 @@ public: void render(const UpdateParameters&); + void flush(); + // Feature queries std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions& options = {}) const; std::vector<Feature> queryRenderedFeatures(const ScreenCoordinate& point, const RenderedQueryOptions& options = {}) const; diff --git a/include/mbgl/renderer/renderer_observer.hpp b/include/mbgl/renderer/renderer_observer.hpp index 0a76d01ca7..1a9d3ff9bc 100644 --- a/include/mbgl/renderer/renderer_observer.hpp +++ b/include/mbgl/renderer/renderer_observer.hpp @@ -31,6 +31,10 @@ public: // Final frame virtual void onDidFinishRenderingMap() {} + + // Style is missing an image + using StyleImageMissingCallback = std::function<void()>; + virtual void onStyleImageMissing(const std::string&, StyleImageMissingCallback done) { done(); } }; } // namespace mbgl diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp index 5f6999e99f..8f88964acf 100644 --- a/include/mbgl/storage/default_file_source.hpp +++ b/include/mbgl/storage/default_file_source.hpp @@ -28,7 +28,7 @@ public: * of megabytes). */ DefaultFileSource(const std::string& cachePath, - const std::string& assetRoot, + const std::string& assetPath, uint64_t maximumCacheSize = util::DEFAULT_MAX_CACHE_SIZE); DefaultFileSource(const std::string& cachePath, std::unique_ptr<FileSource>&& assetFileSource, diff --git a/include/mbgl/storage/file_source.hpp b/include/mbgl/storage/file_source.hpp index 0709a1c245..868dbf7347 100644 --- a/include/mbgl/storage/file_source.hpp +++ b/include/mbgl/storage/file_source.hpp @@ -1,16 +1,21 @@ #pragma once +#include <mbgl/actor/actor_ref.hpp> #include <mbgl/storage/response.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/util/async_request.hpp> +#include <mbgl/util/optional.hpp> #include <functional> #include <memory> namespace mbgl { +class ResourceOptions; +class ResourceTransform; + class FileSource : private util::noncopyable { public: virtual ~FileSource() = default; @@ -31,6 +36,13 @@ public: virtual bool supportsCacheOnlyRequests() const { return false; } + + // Factory for creating a platform-specific file source. + static std::shared_ptr<FileSource> createPlatformFileSource(const ResourceOptions&); + + // Singleton for obtaining the shared platform-specific file source. A single instance of a file source is provided + // for each unique combination of a Mapbox API base URL, access token, cache path and platform context. + static std::shared_ptr<FileSource> getSharedFileSource(const ResourceOptions&); }; } // namespace mbgl diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp index b3d258a7e3..f884c8b465 100644 --- a/include/mbgl/storage/offline.hpp +++ b/include/mbgl/storage/offline.hpp @@ -153,7 +153,7 @@ public: bool requiredResourceCountIsPrecise = false; bool complete() const { - return completedResourceCount == requiredResourceCount; + return completedResourceCount >= requiredResourceCount; } }; diff --git a/include/mbgl/storage/resource_options.hpp b/include/mbgl/storage/resource_options.hpp new file mode 100644 index 0000000000..6d603b8cca --- /dev/null +++ b/include/mbgl/storage/resource_options.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include <memory> +#include <string> + +namespace mbgl { + +/** + * @brief Holds values for resource options. + */ +class ResourceOptions final { +public: + /** + * @brief Constructs a ResourceOptions object with default values. + */ + ResourceOptions(); + ~ResourceOptions(); + + ResourceOptions(ResourceOptions&&) noexcept; + + ResourceOptions clone() const; + + /** + * @brief Sets the Mapbox access token - see https://docs.mapbox.com/help/how-mapbox-works/access-tokens/ for details. + * + * @param token Mapbox access token. + * @return ResourceOptions for chaining options together. + */ + ResourceOptions& withAccessToken(std::string token); + + /** + * @brief Gets the previously set (or default) Mapbox access token. + * + * @return const std::string& Mapbox access token. + */ + const std::string& accessToken() const; + + /** + * @brief Sets the API base URL. Default is https://api.mapbox.com for Mapbox. + * + * @param baseURL API base URL. + * @return ResourceOptions for chaining options together. + */ + ResourceOptions& withBaseURL(std::string baseURL); + + /** + * @brief Gets the previously set (or default) API base URL. + * + * @return const std::string& API base URL. + */ + const std::string& baseURL() const; + + /** + * @brief Sets the cache path. + * + * @param path Cache path. + * @return ResourceOptions for chaining options together. + */ + ResourceOptions& withCachePath(std::string path); + + /** + * @brief Gets the previously set (or default) cache path. + * + * @return cache path + */ + const std::string& cachePath() const; + + /** + * @brief Sets the asset path, which is the root directory from where + * the asset:// scheme gets resolved in a style. + * + * @param path Asset path. + * @return ResourceOptions for chaining options together. + */ + ResourceOptions& withAssetPath(std::string path); + + /** + * @brief Gets the previously set (or default) asset path. + * + * @return asset path + */ + const std::string& assetPath() const; + + /** + * @brief Sets the maximum cache size. + * + * @param size Cache maximum size in bytes. + * @return reference to ResourceOptions for chaining options together. + */ + ResourceOptions& withMaximumCacheSize(uint64_t size); + + /** + * @brief Gets the previously set (or default) maximum allowed cache size. + * + * @return maximum allowed cache database size in bytes. + */ + uint64_t maximumCacheSize() const; + + /** + * @brief Sets the platform context. A platform context is usually an object + * that assists the creation of a file source. + * + * @param context Platform context. + * @return reference to ResourceOptions for chaining options together. + */ + ResourceOptions& withPlatformContext(void* context); + + /** + * @brief Gets the previously set (or default) platform context. + * + * @return Platform context. + */ + void* platformContext() const; + +private: + ResourceOptions(const ResourceOptions&); + + class Impl; + std::unique_ptr<Impl> impl_; +}; + +} // namespace mbgl diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 40657528c4..3a5833be64 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -34,6 +34,11 @@ struct Converter<T, typename std::enable_if_t<std::is_enum<T>::value>> { optional<T> operator()(const Convertible& value, Error& error) const; }; +template <class T> +struct Converter<std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>> { + optional<std::vector<T>> operator()(const Convertible& value, Error& error) const; +}; + template <> struct Converter<Color> { optional<Color> operator()(const Convertible& value, Error& error) const; diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 764f1585f6..35fe72e6bf 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -134,6 +134,14 @@ public: PropertyValue<TextJustifyType> getTextJustify() const; void setTextJustify(PropertyValue<TextJustifyType>); + static PropertyValue<float> getDefaultTextRadialOffset(); + PropertyValue<float> getTextRadialOffset() const; + void setTextRadialOffset(PropertyValue<float>); + + static PropertyValue<std::vector<TextVariableAnchorType>> getDefaultTextVariableAnchor(); + PropertyValue<std::vector<TextVariableAnchorType>> getTextVariableAnchor() const; + void setTextVariableAnchor(PropertyValue<std::vector<TextVariableAnchorType>>); + static PropertyValue<SymbolAnchorType> getDefaultTextAnchor(); PropertyValue<SymbolAnchorType> getTextAnchor() const; void setTextAnchor(PropertyValue<SymbolAnchorType>); diff --git a/include/mbgl/style/types.hpp b/include/mbgl/style/types.hpp index ed875733c7..628e0d2395 100644 --- a/include/mbgl/style/types.hpp +++ b/include/mbgl/style/types.hpp @@ -81,6 +81,7 @@ enum class AlignmentType : uint8_t { }; enum class TextJustifyType : uint8_t { + Auto, Center, Left, Right @@ -98,6 +99,8 @@ enum class SymbolAnchorType : uint8_t { BottomRight }; +using TextVariableAnchorType = SymbolAnchorType; + enum class TextTransformType : uint8_t { None, Uppercase, diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index b39b3a83e9..f7799a953f 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -41,6 +41,9 @@ constexpr float MIN_ZOOM_F = MIN_ZOOM; constexpr float MAX_ZOOM_F = MAX_ZOOM; constexpr uint8_t DEFAULT_MAX_ZOOM = 22; +// ONE_EM constant used to go between "em" units used in style spec and "points" used internally for layout. +constexpr float ONE_EM = 24.0f; + constexpr uint8_t DEFAULT_PREFETCH_ZOOM_DELTA = 4; constexpr uint64_t DEFAULT_MAX_CACHE_SIZE = 50 * 1024 * 1024; diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 7a117f4b2a..55cfd1a6cd 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,48 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +## 7.4.0-alpha.1 - April 3, 2019 + +### Bugs + - Clean up location permissions annotation [#14311](https://github.com/mapbox/mapbox-gl-native/pull/14311) + - Clear camera callbacks' message queue when the map is destroyed [#14292](https://github.com/mapbox/mapbox-gl-native/pull/14292) + - Use a valid gestures focal point when resetting a manager [#14284](https://github.com/mapbox/mapbox-gl-native/pull/14284) + - Disable move gesture detector foreseeing the quickzoom [#14268](https://github.com/mapbox/mapbox-gl-native/pull/14268) + - Remove request render from MapboxMap#onStart [#14245](https://github.com/mapbox/mapbox-gl-native/pull/14245) + - Use TurfMeasurement#distance in LatLng#distanceTo [#14220](https://github.com/mapbox/mapbox-gl-native/pull/14220) + +### Features + - Add pixel dimension annotation to public UiSettings methods [#14281](https://github.com/mapbox/mapbox-gl-native/pull/14281) + - Add #toString override for formatted sections [#14247](https://github.com/mapbox/mapbox-gl-native/pull/14247) + - Harden fetching camera for bounds when padding is excessive [#14221](https://github.com/mapbox/mapbox-gl-native/pull/14221) + - Traverse expression tree when checking for property overrides [#14259](https://github.com/mapbox/mapbox-gl-native/pull/14259) + - Variable label placement [#14184](https://github.com/mapbox/mapbox-gl-native/pull/14184) + +### Build + - Disable binary programs until we fix [#14294]((https://github.com/mapbox/mapbox-gl-native/pull/14298) + - Disable leak canary during instrumentation tests [#14296](https://github.com/mapbox/mapbox-gl-native/pull/14296) + - Remove Android v7 support library [#14265](https://github.com/mapbox/mapbox-gl-native/pull/14265) + +## 7.3.0 - March 28, 2019 + +### Bugs + - Fix MapView reuse issues [#14127](https://github.com/mapbox/mapbox-gl-native/pull/14127) + - Don't call OnSurfaceCreated from the main thread [#14244](https://github.com/mapbox/mapbox-gl-native/pull/14244) + +## 7.3.0-beta.1 - March 20, 2019 + +### Features + - Expose "text-color" option for formatted sections [#14128](https://github.com/mapbox/mapbox-gl-native/pull/14128) + - Expose LocationComponent's layer IDs [#14155](https://github.com/mapbox/mapbox-gl-native/pull/14155) + +### Bugs + - Cache location layer IDs in a set instead of a list [#14141](https://github.com/mapbox/mapbox-gl-native/pull/14141) + - Clear the style object when the map is destroyed [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + - Cache source/layer only when successfully added [#14171](https://github.com/mapbox/mapbox-gl-native/pull/14171) + +### Build + - Bump telemetry version to 4.3.0 [#14140](https://github.com/mapbox/mapbox-gl-native/pull/14140) + ## 7.3.0-alpha.2 - March 13, 2019 ### Features diff --git a/platform/android/LICENSE.md b/platform/android/LICENSE.md index f69b393541..d6f4e65302 100644 --- a/platform/android/LICENSE.md +++ b/platform/android/LICENSE.md @@ -1,11 +1,5 @@ <!-- This file was generated. Use `make android-license` to update. --> ## Additional Mapbox GL licenses -Mapbox GL uses portions of the Android AppCompat Library v7. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Arch-Common. URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -18,18 +12,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox GL uses portions of the Android Lifecycle Extensions. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - -Mapbox GL uses portions of the Android Lifecycle LiveData. -URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) -License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Lifecycle LiveData Core. URL: [https://developer.android.com/topic/libraries/architecture/index.html](https://developer.android.com/topic/libraries/architecture/index.html) License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -54,12 +36,6 @@ License: [The Apache Software License, Version 2.0](http://www.apache.org/licens =========================================================================== -Mapbox GL uses portions of the Android Support AnimatedVectorDrawable. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Android Support Library Annotations. URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -90,12 +66,6 @@ License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2. =========================================================================== -Mapbox GL uses portions of the Android Support VectorDrawable. -URL: [http://developer.android.com/tools/extras/support-library.html](http://developer.android.com/tools/extras/support-library.html) -License: [The Apache Software License](http://www.apache.org/licenses/LICENSE-2.0.txt) - -=========================================================================== - Mapbox GL uses portions of the Converter: Gson. License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) @@ -157,6 +127,12 @@ License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) =========================================================================== +Mapbox GL uses portions of the ReLinker. +URL: [https://github.com/KeepSafe/ReLinker](https://github.com/KeepSafe/ReLinker) +License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + +=========================================================================== + Mapbox GL uses portions of the Retrofit. License: [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 89937448e9..74c7c4c465 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -8,7 +8,6 @@ dependencies { api dependenciesList.mapboxJavaGeoJSON api dependenciesList.mapboxAndroidGestures implementation dependenciesList.mapboxJavaTurf - implementation dependenciesList.supportAppcompatV7 implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.okhttp3 @@ -23,10 +22,6 @@ dependencies { android { compileSdkVersion androidVersions.compileSdkVersion - // Roboelectric 4.0 required config - // http://robolectric.org/migrating/#migrating-to-40 - testOptions.unitTests.includeAndroidResources = true - defaultConfig { minSdkVersion androidVersions.minSdkVersion targetSdkVersion androidVersions.targetSdkVersion @@ -134,12 +129,16 @@ android { testOptions { unitTests { returnDefaultValues true + + // Roboelectric 4.0 required config + // http://robolectric.org/migrating/#migrating-to-40 includeAndroidResources = true } } buildTypes { debug { + testCoverageEnabled true jniDebuggable true } } @@ -169,4 +168,5 @@ apply from: "${rootDir}/gradle/gradle-checkstyle.gradle" apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle" apply from: "${rootDir}/gradle/gradle-update-vendor-modules.gradle" apply from: "${rootDir}/gradle/android-nitpick.gradle" -apply from: "${rootDir}/gradle/gradle-bintray.gradle"
\ No newline at end of file +apply from: "${rootDir}/gradle/gradle-bintray.gradle" +apply from: "${rootDir}/gradle/jacoco-report.gradle"
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index be4246a903..5f3ea808fa 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=7.3.0-SNAPSHOT +VERSION_NAME=7.4.0-SNAPSHOT # Only build native dependencies for the current ABI # See https://code.google.com/p/android/issues/detail?id=221098#c20 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index 8ae388549e..ce12489b49 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 @@ -5,10 +5,14 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.FloatRange; import android.support.annotation.Keep; - import android.support.annotation.NonNull; import android.support.annotation.Nullable; + +import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.constants.GeometryConstants; +import com.mapbox.turf.TurfMeasurement; + +import static com.mapbox.turf.TurfConstants.UNIT_METRES; /** @@ -209,7 +213,8 @@ public class LatLng implements Parcelable { @NonNull public LatLng wrap() { return new LatLng(latitude, wrap(longitude, - GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE)); + GeometryConstants.MIN_WRAP_LONGITUDE, GeometryConstants.MAX_WRAP_LONGITUDE) + ); } @@ -218,8 +223,10 @@ public class LatLng implements Parcelable { * <p> * Same formula as used in Core GL (wrap.hpp) * std::fmod((std::fmod((value - min), d) + d), d) + min; - * + * </p> + * <p> * Multiples of max value will be wrapped to max. + * </p> * * @param value Value to wrap * @param min Minimum value @@ -318,24 +325,10 @@ public class LatLng implements Parcelable { * @return distance in meters */ public double distanceTo(@NonNull LatLng other) { - if (latitude == other.latitude && longitude == other.longitude) { - // return 0.0 to avoid a NaN - return 0.0; - } - - final double a1 = Math.toRadians(this.latitude); - final double a2 = Math.toRadians(this.longitude); - final double b1 = Math.toRadians(other.getLatitude()); - final double b2 = Math.toRadians(other.getLongitude()); - - final double cosa1 = Math.cos(a1); - final double cosb1 = Math.cos(b1); - - final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); - final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); - final double t3 = Math.sin(a1) * Math.sin(b1); - final double tt = Math.acos(t1 + t2 + t3); - - return GeometryConstants.RADIUS_EARTH_METERS * tt; + return TurfMeasurement.distance( + Point.fromLngLat(longitude, latitude), + Point.fromLngLat(other.getLongitude(), other.getLatitude()), + UNIT_METRES + ); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java index 4e56c6e9c0..b9aa371a47 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationCameraController.java @@ -77,9 +77,11 @@ final class LocationCameraController { void initializeOptions(LocationComponentOptions options) { this.options = options; if (options.trackingGesturesManagement()) { - mapboxMap.setGesturesManager(internalGesturesManager, true, true); + if (mapboxMap.getGesturesManager() != internalGesturesManager) { + mapboxMap.setGesturesManager(internalGesturesManager, true, true); + } adjustGesturesThresholds(); - } else { + } else if (mapboxMap.getGesturesManager() != initialGesturesManager) { mapboxMap.setGesturesManager(initialGesturesManager, true, true); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java index b97ab75b5e..327ab3c8ed 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java @@ -220,7 +220,6 @@ public final class LocationComponent { * @param style the proxy object for current map style. More info at {@link Style} * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style) { activateLocationComponent(context, style, @@ -237,7 +236,6 @@ public final class LocationComponent { * there should be no location engine initialized * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine) { @@ -259,7 +257,6 @@ public final class LocationComponent { * @param locationEngineRequest the location request * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine, @@ -284,7 +281,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, boolean useDefaultLocationEngine, @@ -309,7 +305,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @StyleRes int styleRes) { activateLocationComponent(context, style, LocationComponentOptions.createFromAttributes(context, styleRes)); @@ -327,7 +322,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @NonNull LocationComponentOptions options) { @@ -346,7 +340,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @StyleRes int styleRes) { @@ -365,7 +358,6 @@ public final class LocationComponent { * @param styleRes the LocationComponent style res * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -382,7 +374,6 @@ public final class LocationComponent { * @param locationEngine the engine * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine) { @@ -398,7 +389,6 @@ public final class LocationComponent { * @param locationEngineRequest the location request * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -415,7 +405,6 @@ public final class LocationComponent { * @param options the options * @deprecated use {@link LocationComponentActivationOptions.Builder} instead */ - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) @Deprecated public void activateLocationComponent(@NonNull Context context, @NonNull Style style, @Nullable LocationEngine locationEngine, @@ -453,8 +442,7 @@ public final class LocationComponent { * * @param activationOptions a fully built {@link LocationComponentActivationOptions} object */ - public void activateLocationComponent(@NonNull LocationComponentActivationOptions - activationOptions) { + public void activateLocationComponent(@NonNull LocationComponentActivationOptions activationOptions) { LocationComponentOptions options = activationOptions.locationComponentOptions(); if (options == null) { int styleRes = activationOptions.styleRes(); @@ -496,6 +484,7 @@ public final class LocationComponent { * * @param isEnabled true if the plugin should be visible and listen for location updates, false otherwise. */ + @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) public void setLocationComponentEnabled(boolean isEnabled) { checkActivationState(); if (isEnabled) { @@ -954,7 +943,6 @@ public final class LocationComponent { * @return the last known location */ @Nullable - @RequiresPermission(anyOf = {ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION}) public Location getLastKnownLocation() { checkActivationState(); return lastLocation; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java index 093c91e799..c0173cb8e8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentConstants.java @@ -1,7 +1,7 @@ package com.mapbox.mapboxsdk.location; /** - * Contains all the constants being used for the Location layer. + * Contains all the constants being used for the {@link LocationComponent}. */ final class LocationComponentConstants { @@ -49,11 +49,31 @@ final class LocationComponentConstants { static final String PROPERTY_BEARING_ICON = "mapbox-property-shadow-icon"; // Layers - static final String SHADOW_LAYER = "mapbox-location-shadow"; - static final String FOREGROUND_LAYER = "mapbox-location-layer"; - static final String BACKGROUND_LAYER = "mapbox-location-stroke-layer"; - static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer"; - static final String BEARING_LAYER = "mapbox-location-bearing-layer"; + + /** + * Layer ID of the location shadow. + */ + public static final String SHADOW_LAYER = "mapbox-location-shadow-layer"; + + /** + * Layer ID of the location foreground icon. + */ + public static final String FOREGROUND_LAYER = "mapbox-location-foreground-layer"; + + /** + * Layer ID of the location background icon. + */ + public static final String BACKGROUND_LAYER = "mapbox-location-background-layer"; + + /** + * Layer ID of the location accuracy. + */ + public static final String ACCURACY_LAYER = "mapbox-location-accuracy-layer"; + + /** + * Layer ID of the location bearing icon. + */ + public static final String BEARING_LAYER = "mapbox-location-bearing-layer"; // Icons static final String FOREGROUND_ICON = "mapbox-location-icon"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java index f11acacf31..aa8a82bf6d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java @@ -5,6 +5,7 @@ import android.graphics.PointF; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -18,7 +19,6 @@ import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -70,7 +70,8 @@ final class LocationLayerController { private LocationComponentOptions options; private final OnRenderModeChangedListener internalRenderModeChangedListener; - private final List<String> layerMap = new ArrayList<>(); + @VisibleForTesting + final Set<String> layerSet = new HashSet<>(); private Feature locationFeature; private GeoJsonSource locationSource; @@ -112,7 +113,7 @@ final class LocationLayerController { removeLayers(); addLayers(newLayerBelowOption); if (isHidden) { - for (String layerId : layerMap) { + for (String layerId : layerSet) { setLayerVisibility(layerId, false); } } @@ -193,7 +194,7 @@ final class LocationLayerController { void hide() { isHidden = true; - for (String layerId : layerMap) { + for (String layerId : layerSet) { setLayerVisibility(layerId, false); } } @@ -257,14 +258,14 @@ final class LocationLayerController { private void addLayerToMap(Layer layer, @NonNull String idBelowLayer) { style.addLayerBelow(layer, idBelowLayer); - layerMap.add(layer.getId()); + layerSet.add(layer.getId()); } private void removeLayers() { - for (String layerId : layerMap) { + for (String layerId : layerSet) { style.removeLayer(layerId); } - layerMap.clear(); + layerSet.clear(); } private void setBearingProperty(@NonNull String propertyId, float bearing) { @@ -351,7 +352,7 @@ final class LocationLayerController { } private void styleScaling(@NonNull LocationComponentOptions options) { - for (String layerId : layerMap) { + for (String layerId : layerSet) { Layer layer = style.getLayer(layerId); if (layer instanceof SymbolLayer) { layer.setProperties( diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java index b3472ac81e..a1fd4e7e3e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java @@ -142,6 +142,14 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M } } + void onDestroy() { + handler.removeCallbacksAndMessages(null); + onCameraMoveStarted.clear(); + onCameraMoveCanceled.clear(); + onCameraMove.clear(); + onCameraIdle.clear(); + } + private static class CameraChangeHandler extends Handler { private WeakReference<CameraChangeDispatcher> dispatcherWeakReference; 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 c9e6e633aa..9473ea7091 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 @@ -74,7 +74,7 @@ final class MapGestureDetector { * User-set focal point. */ @Nullable - private PointF focalPoint; + private PointF constantFocalPoint; private AndroidGesturesManager gesturesManager; @@ -158,7 +158,7 @@ final class MapGestureDetector { /** * Set the gesture focal point. * <p> - * this is the center point used for calculate transformations from gestures, value is + * This is the center point used for calculate transformations from gestures, value is * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. * </p> * @@ -172,22 +172,7 @@ final class MapGestureDetector { focalPoint = uiSettings.getFocalPoint(); } } - this.focalPoint = focalPoint; - } - - /** - * Get the current active gesture focal point. - * <p> - * This could be either the user provided focal point in - * {@link UiSettings#setFocalPoint(PointF)}or <code>null</code>. - * If it's <code>null</code>, gestures will use focal pointed returned by the detector. - * </p> - * - * @return the current active gesture focal point. - */ - @Nullable - PointF getFocalPoint() { - return focalPoint; + this.constantFocalPoint = focalPoint; } /** @@ -357,18 +342,25 @@ final class MapGestureDetector { int action = motionEvent.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { executeDoubleTap = true; + + // disable the move detector in preparation for the quickzoom, + // so that we don't move the map's center slightly before the quickzoom is started (see #14227) + gesturesManager.getMoveGestureDetector().setEnabled(false); } if (motionEvent.getActionMasked() == MotionEvent.ACTION_UP) { + // re-enabled the move detector + gesturesManager.getMoveGestureDetector().setEnabled(true); + if (!uiSettings.isZoomGesturesEnabled() || !uiSettings.isDoubleTapGesturesEnabled() || !executeDoubleTap) { return false; } PointF zoomFocalPoint; // Single finger double tap - if (focalPoint != null) { + if (constantFocalPoint != null) { // User provided focal point - zoomFocalPoint = focalPoint; + zoomFocalPoint = constantFocalPoint; } else { // Zoom in on gesture zoomFocalPoint = new PointF(motionEvent.getX(), motionEvent.getY()); @@ -468,9 +460,6 @@ final class MapGestureDetector { private final class ScaleGestureListener extends StandardScaleGestureDetector.SimpleStandardOnScaleGestureListener { private final float minimumVelocity; - - @Nullable - private PointF scaleFocalPoint; private boolean quickZoom; ScaleGestureListener(float minimumVelocity) { @@ -496,8 +485,6 @@ final class MapGestureDetector { if (!uiSettings.isQuickZoomGesturesEnabled()) { return false; } - // when quickzoom, disable move gesture - gesturesManager.getMoveGestureDetector().setEnabled(false); } cancelTransitionsIfRequired(); @@ -510,10 +497,7 @@ final class MapGestureDetector { ); } - // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd() - setScaleFocalPoint(detector); - - sendTelemetryEvent(TelemetryConstants.PINCH, scaleFocalPoint); + sendTelemetryEvent(TelemetryConstants.PINCH, getScaleFocalPoint(detector)); notifyOnScaleBeginListeners(detector); @@ -525,11 +509,10 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - setScaleFocalPoint(detector); - float scaleFactor = detector.getScaleFactor(); double zoomBy = getNewZoom(scaleFactor, quickZoom); - transform.zoomBy(zoomBy, scaleFocalPoint); + PointF focalPoint = getScaleFocalPoint(detector); + transform.zoomBy(zoomBy, focalPoint); notifyOnScaleListeners(detector); @@ -538,11 +521,6 @@ final class MapGestureDetector { @Override public void onScaleEnd(@NonNull StandardScaleGestureDetector detector, float velocityX, float velocityY) { - if (quickZoom) { - //if quickzoom, re-enabling move gesture detector - gesturesManager.getMoveGestureDetector().setEnabled(true); - } - if (uiSettings.isIncreaseRotateThresholdWhenScaling()) { // resetting default angle threshold gesturesManager.getRotateGestureDetector().setAngleThreshold( @@ -562,21 +540,23 @@ final class MapGestureDetector { double zoomAddition = calculateScale(velocityXY, detector.isScalingOut()); double currentZoom = transform.getRawZoom(); + PointF focalPoint = getScaleFocalPoint(detector); long animationTime = (long) (Math.abs(zoomAddition) * 1000 / 4); - scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, scaleFocalPoint, animationTime); + scaleAnimator = createScaleAnimator(currentZoom, zoomAddition, focalPoint, animationTime); scheduleAnimator(scaleAnimator); } - private void setScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) { - if (focalPoint != null) { + @NonNull + private PointF getScaleFocalPoint(@NonNull StandardScaleGestureDetector detector) { + if (constantFocalPoint != null) { // around user provided focal point - scaleFocalPoint = focalPoint; + return constantFocalPoint; } else if (quickZoom) { // around center - scaleFocalPoint = new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return new PointF(uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); } else { // around gesture - scaleFocalPoint = detector.getFocalPoint(); + return detector.getFocalPoint(); } } @@ -603,14 +583,12 @@ final class MapGestureDetector { } private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - @Nullable - private PointF rotateFocalPoint; private final float minimumScaleSpanWhenRotating; private final float minimumAngularVelocity; private final float defaultSpanSinceStartThreshold; - public RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity, - float defaultSpanSinceStartThreshold) { + RotateGestureListener(float minimumScaleSpanWhenRotating, float minimumAngularVelocity, + float defaultSpanSinceStartThreshold) { this.minimumScaleSpanWhenRotating = minimumScaleSpanWhenRotating; this.minimumAngularVelocity = minimumAngularVelocity; this.defaultSpanSinceStartThreshold = defaultSpanSinceStartThreshold; @@ -631,10 +609,7 @@ final class MapGestureDetector { gesturesManager.getStandardScaleGestureDetector().interrupt(); } - // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd() - setRotateFocalPoint(detector); - - sendTelemetryEvent(TelemetryConstants.ROTATION, rotateFocalPoint); + sendTelemetryEvent(TelemetryConstants.ROTATION, getRotateFocalPoint(detector)); notifyOnRotateBeginListeners(detector); @@ -647,13 +622,12 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); - setRotateFocalPoint(detector); - // Calculate map bearing value double bearing = transform.getRawBearing() + rotationDegreesSinceLast; // Rotate the map - transform.setBearing(bearing, rotateFocalPoint.x, rotateFocalPoint.y); + PointF focalPoint = getRotateFocalPoint(detector); + transform.setBearing(bearing, focalPoint.x, focalPoint.y); notifyOnRotateListeners(detector); @@ -687,21 +661,24 @@ final class MapGestureDetector { angularVelocity = -angularVelocity; } - rotateAnimator = createRotateAnimator(angularVelocity, animationTime); + PointF focalPoint = getRotateFocalPoint(detector); + rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint); scheduleAnimator(rotateAnimator); } - private void setRotateFocalPoint(@NonNull RotateGestureDetector detector) { - if (focalPoint != null) { + @NonNull + private PointF getRotateFocalPoint(@NonNull RotateGestureDetector detector) { + if (constantFocalPoint != null) { // User provided focal point - rotateFocalPoint = focalPoint; + return constantFocalPoint; } else { // around gesture - rotateFocalPoint = detector.getFocalPoint(); + return detector.getFocalPoint(); } } - private Animator createRotateAnimator(float angularVelocity, long animationTime) { + private Animator createRotateAnimator(float angularVelocity, long animationTime, + @NonNull final PointF animationFocalPoint) { ValueAnimator animator = ValueAnimator.ofFloat(angularVelocity, 0f); animator.setDuration(animationTime); animator.setInterpolator(new DecelerateInterpolator()); @@ -710,7 +687,7 @@ final class MapGestureDetector { public void onAnimationUpdate(@NonNull ValueAnimator animation) { transform.setBearing( transform.getRawBearing() + (float) animation.getAnimatedValue(), - rotateFocalPoint.x, rotateFocalPoint.y, + animationFocalPoint.x, animationFocalPoint.y, 0L ); } @@ -802,9 +779,9 @@ final class MapGestureDetector { PointF zoomFocalPoint; // Single finger double tap - if (focalPoint != null) { + if (constantFocalPoint != null) { // User provided focal point - zoomFocalPoint = focalPoint; + zoomFocalPoint = constantFocalPoint; } else { // Zoom in on gesture zoomFocalPoint = detector.getFocalPoint(); 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 f87c6a854a..23ce2bdef0 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 @@ -911,7 +911,7 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { /** * Called when the map has finished rendering. * - * @param fully true if map is fully rendered, false if fully rendered + * @param fully true if map is fully rendered, false if not fully rendered */ void onDidFinishRenderingMap(boolean fully); } @@ -1257,4 +1257,4 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { public static void setMapStrictModeEnabled(boolean strictModeEnabled) { MapStrictMode.setStrictModeEnabled(strictModeEnabled); } -}
\ No newline at end of file +} 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 f0155bda58..95d5c29b61 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 @@ -128,7 +128,6 @@ public final class MapboxMap { * Called when the hosting Activity/Fragment onStart() method is called. */ void onStart() { - nativeMapView.update(); locationComponent.onStart(); } @@ -174,6 +173,10 @@ public final class MapboxMap { */ void onDestroy() { locationComponent.onDestroy(); + if (style != null) { + style.clear(); + } + cameraChangeDispatcher.onDestroy(); } /** @@ -813,7 +816,7 @@ public final class MapboxMap { public void setStyle(Style.Builder builder, final Style.OnStyleLoaded callback) { locationComponent.onStartLoadingMap(); if (style != null) { - style.onWillStartLoadingMap(); + style.clear(); } if (callback != null) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index cf5961a313..e49126531a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -29,8 +29,6 @@ interface NativeMap { // Lifecycle API // - void update(); - void resizeView(int width, int height); void onLowMemory(); 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 10942d521c..a5f8be788c 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 @@ -136,15 +136,6 @@ final class NativeMapView implements NativeMap { } @Override - public void update() { - if (checkState("update")) { - return; - } - - mapRenderer.requestRender(); - } - - @Override public void resizeView(int width, int height) { if (checkState("resizeView")) { return; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java index f14e034816..5c28b55de8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java @@ -100,8 +100,8 @@ public class Style { */ public void addSource(@NonNull Source source) { validateState("addSource"); - sources.put(source.getId(), source); nativeMap.addSource(source); + sources.put(source.getId(), source); } /** @@ -172,8 +172,8 @@ public class Style { */ public void addLayer(@NonNull Layer layer) { validateState("addLayer"); - layers.put(layer.getId(), layer); nativeMap.addLayer(layer); + layers.put(layer.getId(), layer); } /** @@ -184,8 +184,8 @@ public class Style { */ public void addLayerBelow(@NonNull Layer layer, @NonNull String below) { validateState("addLayerBelow"); - layers.put(layer.getId(), layer); nativeMap.addLayerBelow(layer, below); + layers.put(layer.getId(), layer); } /** @@ -196,8 +196,8 @@ public class Style { */ public void addLayerAbove(@NonNull Layer layer, @NonNull String above) { validateState("addLayerAbove"); - layers.put(layer.getId(), layer); nativeMap.addLayerAbove(layer, above); + layers.put(layer.getId(), layer); } /** @@ -209,8 +209,8 @@ public class Style { */ public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) { validateState("addLayerAbove"); - layers.put(layer.getId(), layer); nativeMap.addLayerAt(layer, index); + layers.put(layer.getId(), layer); } /** @@ -437,10 +437,11 @@ public class Style { // /** - * Called when the underlying map will start loading a new style. This method will clean up this style - * by setting the java sources and layers in a detached state and removing them from core. + * Called when the underlying map will start loading a new style or the map is destroyed. + * This method will clean up this style by setting the java sources and layers + * in a detached state and removing them from core. */ - void onWillStartLoadingMap() { + void clear() { fullyLoaded = false; for (Source source : sources.values()) { if (source != null) { 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 034dc63c35..c671146876 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 @@ -10,6 +10,7 @@ import android.os.Bundle; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.annotation.Px; import android.support.annotation.UiThread; import android.support.v4.content.ContextCompat; import android.support.v4.content.res.ResourcesCompat; @@ -344,7 +345,7 @@ public final class UiSettings { } /** - * Sets the margins of the compass view. Use this to change the distance of the compass from the + * Sets the margins of the compass view in pixels. Use this to change the distance of the compass from the * map view edge. * * @param left The left margin in pixels. @@ -353,42 +354,46 @@ public final class UiSettings { * @param bottom The bottom margin in pixels. */ @UiThread - public void setCompassMargins(int left, int top, int right, int bottom) { + public void setCompassMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(compassView, compassMargins, left, top, right, bottom); } /** - * Returns the left side margin of CompassView + * Returns the left side margin of CompassView in pixels. * * @return The left margin in pixels */ + @Px public int getCompassMarginLeft() { return compassMargins[0]; } /** - * Returns the top side margin of CompassView + * Returns the top side margin of CompassView in pixels. * * @return The top margin in pixels */ + @Px public int getCompassMarginTop() { return compassMargins[1]; } /** - * Returns the right side margin of CompassView + * Returns the right side margin of CompassView in pixels. * * @return The right margin in pixels */ + @Px public int getCompassMarginRight() { return compassMargins[2]; } /** - * Returns the bottom side margin of CompassView + * Returns the bottom side margin of CompassView in pixels. * * @return The bottom margin in pixels */ + @Px public int getCompassMarginBottom() { return compassMargins[3]; } @@ -456,7 +461,7 @@ public final class UiSettings { } /** - * Sets the margins of the logo view. Use this to change the distance of the Mapbox logo from the + * Sets the margins of the logo view in pixels. Use this to change the distance of the Mapbox logo from the * map view edge. * * @param left The left margin in pixels. @@ -464,42 +469,46 @@ public final class UiSettings { * @param right The right margin in pixels. * @param bottom The bottom margin in pixels. */ - public void setLogoMargins(int left, int top, int right, int bottom) { + public void setLogoMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(logoView, logoMargins, left, top, right, bottom); } /** - * Returns the left side margin of the logo + * Returns the left side margin of the logo in pixels. * * @return The left margin in pixels */ + @Px public int getLogoMarginLeft() { return logoMargins[0]; } /** - * Returns the top side margin of the logo + * Returns the top side margin of the logo in pixels. * * @return The top margin in pixels */ + @Px public int getLogoMarginTop() { return logoMargins[1]; } /** - * Returns the right side margin of the logo + * Returns the right side margin of the logo in pixels. * * @return The right margin in pixels */ + @Px public int getLogoMarginRight() { return logoMargins[2]; } /** - * Returns the bottom side margin of the logo + * Returns the bottom side margin of the logo in pixels. * * @return The bottom margin in pixels */ + @Px public int getLogoMarginBottom() { return logoMargins[3]; } @@ -570,14 +579,14 @@ public final class UiSettings { } /** - * Sets the margins of the attribution view. + * Sets the margins of the attribution view in pixels. * * @param left The left margin in pixels. * @param top The top margin in pixels. * @param right The right margin in pixels. * @param bottom The bottom margin in pixels. */ - public void setAttributionMargins(int left, int top, int right, int bottom) { + public void setAttributionMargins(@Px int left, @Px int top, @Px int right, @Px int bottom) { setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom); } @@ -599,37 +608,41 @@ public final class UiSettings { } /** - * Returns the left side margin of the attribution view. + * Returns the left side margin of the attribution view in pixels. * * @return The left margin in pixels */ + @Px public int getAttributionMarginLeft() { return attributionsMargins[0]; } /** - * Returns the top side margin of the attribution view. + * Returns the top side margin of the attribution view in pixels. * * @return The top margin in pixels */ + @Px public int getAttributionMarginTop() { return attributionsMargins[1]; } /** - * Returns the right side margin of the attribution view. + * Returns the right side margin of the attribution view in pixels. * * @return The right margin in pixels */ + @Px public int getAttributionMarginRight() { return attributionsMargins[2]; } /** - * Returns the bottom side margin of the logo + * Returns the bottom side margin of the logo in pixels. * * @return The bottom margin in pixels */ + @Px public int getAttributionMarginBottom() { return attributionsMargins[3]; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java index 9d9a7bd2d4..524c1a62ee 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java @@ -2,10 +2,8 @@ package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview; import android.content.Context; import android.opengl.GLSurfaceView; - import android.support.annotation.NonNull; import android.view.SurfaceHolder; - import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser; @@ -25,8 +23,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @NonNull private final GLSurfaceView glSurfaceView; - private boolean requestDestroy; - public GLSurfaceViewMapRenderer(Context context, GLSurfaceView glSurfaceView, String localIdeographFontFamily) { @@ -42,9 +38,8 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @Override public void surfaceDestroyed(SurfaceHolder holder) { - requestDestroy = true; + onSurfaceDestroyed(); } - }); } @@ -60,9 +55,6 @@ public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceVi @Override public void onDestroy() { - if (requestDestroy) { - onSurfaceDestroyed(); - } super.onDestroy(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java index 96d5e9e943..165b15a512 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java @@ -197,7 +197,6 @@ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextu if (destroySurface) { eglHolder.destroySurface(); destroySurface = false; - mapRenderer.onSurfaceDestroyed(); break; } 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 6262418a29..53c0c1c60f 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 @@ -7,10 +7,10 @@ import android.support.annotation.Nullable; 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.maps.MapboxMap; @@ -23,7 +23,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; * use {@link com.mapbox.mapboxsdk.maps.UiSettings}. * </p> */ -public final class CompassView extends AppCompatImageView implements Runnable { +public final class CompassView extends ImageView implements Runnable { public static final long TIME_WAIT_IDLE = 500; public static final long TIME_MAP_NORTH_ANIMATION = 150; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java index b88e1885ca..12d1fe46cf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEvent.java @@ -1,20 +1,55 @@ package com.mapbox.mapboxsdk.module.telemetry; +import com.google.gson.Gson; + +import com.google.gson.JsonObject; + +import com.google.gson.reflect.TypeToken; import com.mapbox.android.telemetry.Event; import android.os.Bundle; import android.os.Parcel; + import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Locale; /** * Generic Performance Event that can be used for performance measurements. * Customer measurements can be added to the bundle. + * + * Bundle is expected to have following properties: + * "attributes", "counters", and "metadata" with String values. + * + * Attributes: a string representing an array of name/string value pair objects. + * Counters: a string representing an array of name/number value pair objects. + * Metadata is a string representation of a JsonObject with string values. + * + * Here is an example of a Performance event bundle data: + * + * "attributes": [{ "name": "style_id", "value": "mapbox://styles/mapbox/streets-v10"}] + * + * "counters": [{"name": "fps_average", "value": 90.7655486547093}, + * {"name": "fps_deviation", "value": 29.301809631465574}] + * “metadata”: { + * “version”: “9”, + * “screenSize”: “1080x1794”, + * “country”: “US”, + * “device”: “Pixel 2”, + * “abi”: “arm64-v8a”, + * “brand”: “google”, + * “ram”: “3834167296”, + * “os”: “android”, + * “gpu”: “Qualcomm, Adreno (TM) 540, OpenGL ES 3.2 V@313.0 (GIT@7bf2852, Ie32bfa6f6f)“, + * “manufacturer”: “Google” + * } */ public class PerformanceEvent extends Event { - private static final String PERFORMANCE_TRACE = "performance.trace"; + + private static final String PERFORMANCE_TRACE = "mobile.performance_trace"; private final String event; @@ -22,23 +57,36 @@ public class PerformanceEvent extends Event { private final String sessionId; - private final Bundle data; + private final List<Attribute<String>> attributes; + + private final List<Attribute<Double>> counters; + + private final JsonObject metadata; + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US); - PerformanceEvent(String sessionId, Bundle data) { + PerformanceEvent(String sessionId, Bundle bundle) { + this.event = PERFORMANCE_TRACE; this.created = DATE_FORMAT.format(new Date()); this.sessionId = sessionId; - this.data = data; + this.attributes = initList(bundle.getString("attributes"), + new TypeToken<ArrayList<Attribute<String>>>() {}); + this.counters = initList(bundle.getString("counters"), + new TypeToken<ArrayList<Attribute<Double>>>() {}); + this.metadata = initMetaData(bundle.getString("metadata")); } private PerformanceEvent(Parcel in) { this.event = in.readString(); this.created = in.readString(); this.sessionId = in.readString(); - this.data = in.readBundle(); + + this.attributes = initList(in.readString(), new TypeToken<ArrayList<Attribute<String>>>() {}); + this.counters = initList(in.readString(), new TypeToken<ArrayList<Attribute<Double>>>() {}); + this.metadata = initMetaData(in.readString()); } @Override @@ -51,7 +99,30 @@ public class PerformanceEvent extends Event { parcel.writeString(event); parcel.writeString(created); parcel.writeString(sessionId); - parcel.writeBundle(data); + + Gson gson = new Gson(); + + parcel.writeString(gson.toJson(attributes)); + parcel.writeString(gson.toJson(counters)); + + if (metadata != null) { + parcel.writeString(metadata.toString()); + } + } + + private <T> ArrayList<Attribute<T>> initList(String fromString, TypeToken typeToken) { + if (fromString == null || fromString.isEmpty()) { + return new ArrayList<>(); + } + return new Gson().fromJson(fromString, typeToken.getType()); + } + + private JsonObject initMetaData(String fromString) { + if (fromString == null) { + return new JsonObject(); + } else { + return new Gson().fromJson(fromString, JsonObject.class); + } } public static final Creator<PerformanceEvent> CREATOR = new Creator<PerformanceEvent>() { @@ -65,4 +136,15 @@ public class PerformanceEvent extends Event { return new PerformanceEvent[size]; } }; + + + private class Attribute<T> { + private final String name; + private final T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java index 5e021f961e..697a51286f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/module/telemetry/TelemetryImpl.java @@ -111,8 +111,9 @@ public class TelemetryImpl implements TelemetryDefinition { @Override public void onPerformanceEvent(Bundle data) { - if (data != null && !data.isEmpty()) { - telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data)); + if (data == null) { + data = new Bundle(); } + telemetry.push(new PerformanceEvent(UUID.randomUUID().toString(), data)); } }
\ No newline at end of file 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 01ac098d16..8684d7c6f1 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 @@ -26,7 +26,11 @@ import java.nio.channels.FileChannel; /** * The offline manager is the main entry point for offline-related functionality. + * <p> * It'll help you list and create offline regions. + * </p> + * + * @see <a href="https://docs.mapbox.com/help/troubleshooting/mobile-offline/">Offline Maps Information/</a> */ public class OfflineManager { 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 1c87b9004b..57cf6271c9 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 @@ -323,6 +323,10 @@ public final class Property { // TEXT_JUSTIFY: Text justification options. /** + * The text is aligned towards the anchor position. + */ + public static final String TEXT_JUSTIFY_AUTO = "auto"; + /** * The text is aligned to the left. */ public static final String TEXT_JUSTIFY_LEFT = "left"; @@ -339,6 +343,7 @@ public final class Property { * Text justification options. */ @StringDef({ + TEXT_JUSTIFY_AUTO, TEXT_JUSTIFY_LEFT, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_RIGHT, 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 3d8b921a79..01908b1b0b 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 @@ -2276,6 +2276,46 @@ public class PropertyFactory { } /** + * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue<Float> textRadialOffset(Float value) { + return new LayoutPropertyValue<>("text-radial-offset", value); + } + + /** + * Radial offset of text, in the direction of the symbol's anchor. Useful in combination with {@link PropertyFactory#textVariableAnchor}, which doesn't support the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a Float value + * @return property wrapper around Float + */ + public static PropertyValue<Expression> textRadialOffset(Expression value) { + return new LayoutPropertyValue<>("text-radial-offset", value); + } + + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a String[] value + * @return property wrapper around String[] + */ + public static PropertyValue<String[]> textVariableAnchor(String[] value) { + return new LayoutPropertyValue<>("text-variable-anchor", value); + } + + /** + * To increase the chance of placing high-priority labels on the map, you can provide an array of {@link Property.TEXT_ANCHOR} locations: the render will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the {@link PropertyFactory#textRadialOffset} instead of the two-dimensional {@link PropertyFactory#textOffset}. + * + * @param value a String[] value + * @return property wrapper around String[] + */ + public static PropertyValue<Expression> textVariableAnchor(Expression value) { + return new LayoutPropertyValue<>("text-variable-anchor", value); + } + + /** * Part of the text placed closest to the anchor. * * @param value a String value 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 ab45cb04f2..75473f0f30 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 @@ -470,6 +470,30 @@ public class SymbolLayer extends Layer { } /** + * Get the TextRadialOffset property + * + * @return property wrapper value around Float + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue<Float> getTextRadialOffset() { + checkThread(); + return (PropertyValue<Float>) new PropertyValue("text-radial-offset", nativeGetTextRadialOffset()); + } + + /** + * Get the TextVariableAnchor property + * + * @return property wrapper value around String[] + */ + @NonNull + @SuppressWarnings("unchecked") + public PropertyValue<String[]> getTextVariableAnchor() { + checkThread(); + return (PropertyValue<String[]>) new PropertyValue("text-variable-anchor", nativeGetTextVariableAnchor()); + } + + /** * Get the TextAnchor property * * @return property wrapper value around String @@ -1187,6 +1211,14 @@ public class SymbolLayer extends Layer { @NonNull @Keep + private native Object nativeGetTextRadialOffset(); + + @NonNull + @Keep + private native Object nativeGetTextVariableAnchor(); + + @NonNull + @Keep private native Object nativeGetTextAnchor(); @NonNull diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java index fb2d361bfc..b76e4f4417 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/Formatted.java @@ -58,4 +58,12 @@ public class Formatted { public int hashCode() { return Arrays.hashCode(formattedSections); } + + @Override + public String toString() { + return "Formatted{" + + "formattedSections=" + + Arrays.toString(formattedSections) + + '}'; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java index a5b0dfbfe8..859fcff378 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/types/FormattedSection.java @@ -228,4 +228,14 @@ public class FormattedSection { params.put("text-color", textColor); return new Object[] {text, params}; } + + @Override + public String toString() { + return "FormattedSection{" + + "text='" + text + '\'' + + ", fontScale=" + fontScale + + ", fontStack=" + Arrays.toString(fontStack) + + ", textColor='" + textColor + '\'' + + '}'; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java index 3ef8e93cae..3570aa2c0b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java @@ -13,7 +13,6 @@ import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; -import android.support.v7.content.res.AppCompatResources; import android.view.View; import java.io.ByteArrayOutputStream; @@ -152,7 +151,7 @@ public class BitmapUtils { @Nullable public static Drawable getDrawableFromRes(@NonNull Context context, @DrawableRes int drawableRes, @Nullable @ColorInt Integer tintColor) { - Drawable drawable = AppCompatResources.getDrawable(context, drawableRes); + Drawable drawable = context.getResources().getDrawable(drawableRes); if (drawable == null) { return null; } 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 1adbe7e769..e5cde7e441 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 @@ -7,14 +7,14 @@ android:layout_height="wrap_content" android:contentDescription="@string/mapbox_compassContentDescription"/> - <android.support.v7.widget.AppCompatImageView + <ImageView android:visibility="gone" android:id="@+id/logoView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:contentDescription="@null"/> - <android.support.v7.widget.AppCompatImageView + <ImageView android:visibility="gone" android:id="@+id/attributionView" android:layout_width="wrap_content" diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java index 8e47f069c3..862c56a526 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java @@ -175,7 +175,7 @@ public class LatLngTest { LatLng latLng2 = new LatLng(1.0, 1.0); assertEquals("distances should match", latLng1.distanceTo(latLng2), - 157425.53710839353, DELTA); + 157298.7453847275, DELTA); } @Test @@ -186,6 +186,15 @@ public class LatLngTest { assertEquals("distance should match", 0.0, distance, DELTA); } + // Regression test for #14216 + @Test + public void testDistanceToClosePointNotNaN() { + LatLng latLng = new LatLng(40.00599, -105.29261); + LatLng other = new LatLng(40.005990000000025, -105.29260999999997); + double distance = latLng.distanceTo(other); + assertNotEquals(distance, Double.NaN); + } + @Test public void testLocationProvider() { double latitude = 1.2; diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java index 56a8f276a7..a3d54fe221 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationCameraControllerTest.java @@ -408,6 +408,7 @@ public class LocationCameraControllerTest { MapboxMap mapboxMap = mock(MapboxMap.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); LocationComponentOptions options = mock(LocationComponentOptions.class); when(options.trackingGesturesManagement()).thenReturn(true); @@ -421,6 +422,7 @@ public class LocationCameraControllerTest { MapboxMap mapboxMap = mock(MapboxMap.class); AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); LocationComponentOptions options = mock(LocationComponentOptions.class); when(options.trackingGesturesManagement()).thenReturn(false); @@ -430,6 +432,34 @@ public class LocationCameraControllerTest { } @Test + public void gesturesManagement_optionNotChangedInitial() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(initialGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(false); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(initialGesturesManager, true, true); + } + + @Test + public void gesturesManagement_optionNotChangedInternal() { + MapboxMap mapboxMap = mock(MapboxMap.class); + AndroidGesturesManager initialGesturesManager = mock(AndroidGesturesManager.class); + AndroidGesturesManager internalGesturesManager = mock(AndroidGesturesManager.class); + when(mapboxMap.getGesturesManager()).thenReturn(internalGesturesManager); + LocationCameraController camera = buildCamera(mapboxMap, initialGesturesManager, internalGesturesManager); + LocationComponentOptions options = mock(LocationComponentOptions.class); + when(options.trackingGesturesManagement()).thenReturn(true); + camera.initializeOptions(options); + + verify(mapboxMap, times(0)).setGesturesManager(internalGesturesManager, true, true); + } + + @Test public void onMove_notCancellingTransitionWhileNone() { MapboxMap mapboxMap = mock(MapboxMap.class); when(mapboxMap.getUiSettings()).thenReturn(mock(UiSettings.class)); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java index 10553700b3..6a44cf1f79 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java @@ -39,6 +39,7 @@ import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_ACCURA import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_COMPASS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_GPS_BEARING; import static com.mapbox.mapboxsdk.location.MapboxAnimator.ANIMATOR_LAYER_LATLNG; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -160,6 +161,24 @@ public class LocationLayerControllerTest { } @Test + public void onInitialization_numberOfCachedLayerIdsIsConstant() { + OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); + LayerSourceProvider sourceProvider = buildLayerProvider(); + GeoJsonSource locationSource = mock(GeoJsonSource.class); + when(sourceProvider.generateSource(any(Feature.class))).thenReturn(locationSource); + LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); + LocationComponentOptions options = mock(LocationComponentOptions.class); + + LocationLayerController controller = + new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options), + bitmapProvider, options, internalRenderModeChangedListener); + + controller.initializeComponents(mapboxMap.getStyle(), options); + + assertEquals(5, controller.layerSet.size()); + } + + @Test public void applyStyle_styleShadowWithValidElevation() { OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class); LayerSourceProvider sourceProvider = buildLayerProvider(); @@ -300,22 +319,6 @@ public class LocationLayerControllerTest { LayerSourceProvider sourceProvider = buildLayerProvider(); when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class)); - Layer bearingLayer = mock(Layer.class); - when(bearingLayer.getId()).thenReturn(BEARING_LAYER); - when(sourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); - Layer foregroundLayer = mock(Layer.class); - when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER); - when(sourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); - Layer backgroundLayer = mock(Layer.class); - when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER); - when(sourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); - Layer shadowLayer = mock(Layer.class); - when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); - when(sourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); - Layer accuracyLayer = mock(Layer.class); - when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); - when(sourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); - LocationComponentOptions options = mock(LocationComponentOptions.class); LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class); Bitmap bitmap = mock(Bitmap.class); @@ -606,18 +609,23 @@ public class LocationLayerControllerTest { LayerSourceProvider layerSourceProvider = mock(LayerSourceProvider.class); Layer shadowLayer = mock(Layer.class); + when(shadowLayer.getId()).thenReturn(SHADOW_LAYER); when(layerSourceProvider.generateLayer(SHADOW_LAYER)).thenReturn(shadowLayer); Layer backgroundLayer = mock(Layer.class); + when(backgroundLayer.getId()).thenReturn(BACKGROUND_LAYER); when(layerSourceProvider.generateLayer(BACKGROUND_LAYER)).thenReturn(backgroundLayer); Layer foregroundLayer = mock(Layer.class); + when(foregroundLayer.getId()).thenReturn(FOREGROUND_LAYER); when(layerSourceProvider.generateLayer(FOREGROUND_LAYER)).thenReturn(foregroundLayer); Layer bearingLayer = mock(Layer.class); + when(bearingLayer.getId()).thenReturn(BEARING_LAYER); when(layerSourceProvider.generateLayer(BEARING_LAYER)).thenReturn(bearingLayer); Layer accuracyLayer = mock(Layer.class); + when(accuracyLayer.getId()).thenReturn(ACCURACY_LAYER); when(layerSourceProvider.generateAccuracyLayer()).thenReturn(accuracyLayer); return layerSourceProvider; } diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt index a0873e97ff..2d68612c70 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -15,31 +15,33 @@ import org.robolectric.RobolectricTestRunner @RunWith(RobolectricTestRunner::class) class MapboxMapTest { - private lateinit var mapboxMap: MapboxMap - - private lateinit var nativeMapView: NativeMapView - - private lateinit var transform: Transform - - @Before - fun setup() { - val cameraChangeDispatcher = spyk<CameraChangeDispatcher>() - nativeMapView = mockk(relaxed = true) - transform = mockk(relaxed = true) - mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher) - every { nativeMapView.isDestroyed } returns false - every { nativeMapView.nativePtr } returns 5 - mapboxMap.injectLocationComponent(spyk()) - mapboxMap.setStyle(Style.MAPBOX_STREETS) - mapboxMap.onFinishLoadingStyle() - } - - @Test - fun testTransitionOptions() { - val expected = TransitionOptions(100, 200) - mapboxMap.style?.transition = expected - verify { nativeMapView.transitionOptions = expected } - } + private lateinit var mapboxMap: MapboxMap + + private lateinit var nativeMapView: NativeMapView + + private lateinit var transform: Transform + + private lateinit var cameraChangeDispatcher: CameraChangeDispatcher + + @Before + fun setup() { + cameraChangeDispatcher = spyk() + nativeMapView = mockk(relaxed = true) + transform = mockk(relaxed = true) + mapboxMap = MapboxMap(nativeMapView, transform, mockk(relaxed = true), null, null, cameraChangeDispatcher) + every { nativeMapView.isDestroyed } returns false + every { nativeMapView.nativePtr } returns 5 + mapboxMap.injectLocationComponent(spyk()) + mapboxMap.setStyle(Style.MAPBOX_STREETS) + mapboxMap.onFinishLoadingStyle() + } + + @Test + fun testTransitionOptions() { + val expected = TransitionOptions(100, 200) + mapboxMap.style?.transition = expected + verify { nativeMapView.transitionOptions = expected } + } @Test fun testMoveCamera() { @@ -51,52 +53,52 @@ class MapboxMapTest { verify { transform.moveCamera(mapboxMap, update, callback) } } - @Test - fun testMinZoom() { - mapboxMap.setMinZoomPreference(10.0) - verify { transform.minZoom = 10.0 } - } - - @Test - fun testMaxZoom() { - mapboxMap.setMaxZoomPreference(10.0) - verify { transform.maxZoom = 10.0 } - } - - @Test - fun testFpsListener() { - val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>() - mapboxMap.onFpsChangedListener = fpsChangedListener - assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener) - } - - @Test - fun testTilePrefetch() { - mapboxMap.prefetchesTiles = true - verify { nativeMapView.prefetchTiles = true } - } - - @Test - fun testCameraForLatLngBounds() { - val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() - mapboxMap.setLatLngBoundsForCameraTarget(bounds) - verify { nativeMapView.setLatLngBounds(bounds) } - } - - @Test(expected = IllegalArgumentException::class) - fun testAnimateCameraChecksDurationPositive() { - mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) - } - - @Test(expected = IllegalArgumentException::class) - fun testEaseCameraChecksDurationPositive() { - mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) - } - - @Test - fun testGetNativeMapPtr() { - assertEquals(5, mapboxMap.nativeMapPtr) - } + @Test + fun testMinZoom() { + mapboxMap.setMinZoomPreference(10.0) + verify { transform.minZoom = 10.0 } + } + + @Test + fun testMaxZoom() { + mapboxMap.setMaxZoomPreference(10.0) + verify { transform.maxZoom = 10.0 } + } + + @Test + fun testFpsListener() { + val fpsChangedListener = mockk<MapboxMap.OnFpsChangedListener>() + mapboxMap.onFpsChangedListener = fpsChangedListener + assertEquals("Listener should match", fpsChangedListener, mapboxMap.onFpsChangedListener) + } + + @Test + fun testTilePrefetch() { + mapboxMap.prefetchesTiles = true + verify { nativeMapView.prefetchTiles = true } + } + + @Test + fun testCameraForLatLngBounds() { + val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() + mapboxMap.setLatLngBoundsForCameraTarget(bounds) + verify { nativeMapView.setLatLngBounds(bounds) } + } + + @Test(expected = IllegalArgumentException::class) + fun testAnimateCameraChecksDurationPositive() { + mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test(expected = IllegalArgumentException::class) + fun testEaseCameraChecksDurationPositive() { + mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(LatLng(30.0, 30.0)), 0, null) + } + + @Test + fun testGetNativeMapPtr() { + assertEquals(5, mapboxMap.nativeMapPtr) + } @Test fun testNativeMapIsNotCalledOnStateSave() { @@ -104,4 +106,10 @@ class MapboxMapTest { mapboxMap.onSaveInstanceState(mockk(relaxed = true)) verify { nativeMapView wasNot Called } } + + @Test + fun testCameraChangeDispatcherCleared() { + mapboxMap.onDestroy() + verify { cameraChangeDispatcher.onDestroy() } + } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 22222b0f50..190c279e03 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -9,7 +9,7 @@ android { targetSdkVersion androidVersions.targetSdkVersion versionCode 13 versionName "6.0.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "com.mapbox.mapboxsdk.InstrumentationRunner" } compileOptions { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json new file mode 100644 index 0000000000..5ab289344a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/assets/streets.json @@ -0,0 +1,5331 @@ +{ + "version": 8, + "name": "mapbox-gl-native-test-style", + "metadata": { + "mapbox:autocomposite": true, + "mapbox:type": "default", + "mapbox:origin": "streets-v10", + "mapbox:groups": { + "1444934828655.3389": {"name": "Aeroways", "collapsed": true}, + "1444933322393.2852": { + "name": "POI labels (scalerank 1)", + "collapsed": true + }, + "1444855786460.0557": {"name": "Roads", "collapsed": true}, + "1444933575858.6992": { + "name": "Highway shields", + "collapsed": true + }, + "1444934295202.7542": { + "name": "Admin boundaries", + "collapsed": true + }, + "1444856151690.9143": {"name": "State labels", "collapsed": true}, + "1444933721429.3076": {"name": "Road labels", "collapsed": true}, + "1444933358918.2366": { + "name": "POI labels (scalerank 2)", + "collapsed": true + }, + "1444933808272.805": {"name": "Water labels", "collapsed": true}, + "1444933372896.5967": { + "name": "POI labels (scalerank 3)", + "collapsed": true + }, + "1444855799204.86": {"name": "Bridges", "collapsed": true}, + "1444856087950.3635": {"name": "Marine labels", "collapsed": true}, + "1456969573402.7817": {"name": "Hillshading", "collapsed": true}, + "1444862510685.128": {"name": "City labels", "collapsed": true}, + "1444855769305.6016": {"name": "Tunnels", "collapsed": true}, + "1456970288113.8113": {"name": "Landcover", "collapsed": true}, + "1444856144497.7825": {"name": "Country labels", "collapsed": true}, + "1444933456003.5437": { + "name": "POI labels (scalerank 4)", + "collapsed": true + } + }, + "mapbox:sdk-support": { + "js": "0.49.0", + "android": "6.5.0", + "ios": "4.4.0" + } + }, + "center": [0.0, 0.0], + "zoom": 0, + "bearing": 0, + "pitch": 0, + "sources": { + "composite": { + "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/lukaspaczos/cjnkdt02b0b2p2ss40skwpvs1", + "glyphs": "mapbox://fonts/lukaspaczos/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {}, + "paint": { + "background-color": { + "base": 1, + "stops": [ + [11, "hsl(35, 32%, 91%)"], + [13, "hsl(35, 12%, 89%)"] + ] + } + } + }, + { + "id": "landcover_snow", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "filter": ["==", "class", "snow"], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": 0.2, + "fill-antialias": false + } + }, + { + "id": "landcover_wood", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "wood"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_scrub", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "scrub"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_grass", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "grass"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "landcover_crop", + "type": "fill", + "metadata": {"mapbox:group": "1456970288113.8113"}, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": ["==", "class", "crop"], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": {"base": 1.5, "stops": [[2, 0.3], [7, 0]]}, + "fill-antialias": false + } + }, + { + "id": "national_park", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "filter": ["==", "class", "national_park"], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 0.5]]} + } + }, + { + "id": "hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "hospital"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(340, 37%, 87%)"], + [16, "hsl(340, 63%, 89%)"] + ] + } + } + }, + { + "id": "school", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "school"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(50, 47%, 81%)"], + [16, "hsl(50, 63%, 84%)"] + ] + } + } + }, + { + "id": "park", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "park"], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": {"base": 1, "stops": [[5, 0], [6, 1]]} + } + }, + { + "id": "pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "pitch"], + "layout": {}, + "paint": {"fill-color": "hsl(100, 57%, 72%)"} + }, + { + "id": "pitch-line", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "minzoom": 15, + "filter": ["==", "class", "pitch"], + "layout": {"line-join": "miter"}, + "paint": {"line-color": "hsl(75, 57%, 84%)"} + }, + { + "id": "cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "cemetery"], + "layout": {}, + "paint": {"fill-color": "hsl(75, 37%, 81%)"} + }, + { + "id": "industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "industrial"], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15.5, "hsl(230, 15%, 86%)"], + [16, "hsl(230, 29%, 89%)"] + ] + } + } + }, + { + "id": "sand", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": ["==", "class", "sand"], + "layout": {}, + "paint": {"fill-color": "hsl(60, 46%, 87%)"} + }, + { + "id": "hillshade_highlight_bright", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 94], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": {"stops": [[14, 0.12], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_highlight_med", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 90], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": {"stops": [[14, 0.12], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_faint", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 89], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.05], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_med", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 78], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.05], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_dark", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 67], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.06], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "hillshade_shadow_extreme", + "type": "fill", + "metadata": {"mapbox:group": "1456969573402.7817"}, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": ["==", "level", 56], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": {"stops": [[14, 0.06], [16, 0]]}, + "fill-antialias": false + } + }, + { + "id": "waterway-river-canal", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 8, + "filter": ["in", "class", "canal", "river"], + "layout": { + "line-cap": {"base": 1, "stops": [[0, "butt"], [11, "round"]]}, + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": {"base": 1.3, "stops": [[8.5, 0.1], [20, 8]]}, + "line-opacity": {"base": 1, "stops": [[8, 0], [8.5, 1]]} + } + }, + { + "id": "waterway-small", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 13, + "filter": ["!in", "class", "canal", "river"], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": {"base": 1.35, "stops": [[13.5, 0.1], [20, 3]]}, + "line-opacity": {"base": 1, "stops": [[13, 0], [13.5, 1]]} + } + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(215, 84%, 69%)", + "fill-translate": { + "base": 1.2, + "stops": [[7, [0, 0]], [16, [-1, -1]]] + }, + "fill-translate-anchor": "viewport", + "fill-opacity": 1 + } + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": {"fill-color": "hsl(196, 80%, 70%)"} + }, + { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + ["==", "$type", "Polygon"], + ["==", "class", "land"] + ], + "layout": {}, + "paint": {"fill-color": "hsl(35, 12%, 89%)"} + }, + { + "id": "barrier_line-land-line", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "class", "land"] + ], + "layout": {"line-cap": "round"}, + "paint": { + "line-width": {"base": 1.99, "stops": [[14, 0.75], [20, 40]]}, + "line-color": "hsl(35, 12%, 89%)" + } + }, + { + "id": "aeroway-polygon", + "type": "fill", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ + "all", + ["!=", "type", "apron"], + ["==", "$type", "Polygon"] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "fill-opacity": {"base": 1, "stops": [[11, 0], [11.5, 1]]} + } + }, + { + "id": "aeroway-runway", + "type": "line", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "runway"] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[9, 1], [18, 80]]} + } + }, + { + "id": "aeroway-taxiway", + "type": "line", + "metadata": {"mapbox:group": "1444934828655.3389"}, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "taxiway"] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(230, 23%, 82%)"], + [16, "hsl(230, 37%, 84%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[10, 0.5], [18, 20]]} + } + }, + { + "id": "building-line", + "type": "line", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + ["!=", "type", "building:part"], + ["==", "underground", "false"] + ], + "layout": {}, + "paint": { + "line-color": "hsl(35, 6%, 79%)", + "line-width": {"base": 1.5, "stops": [[15, 0.75], [20, 3]]}, + "line-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]} + } + }, + { + "id": "building", + "type": "fill", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + ["!=", "type", "building:part"], + ["==", "underground", "false"] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [15, "hsl(35, 11%, 88%)"], + [16, "hsl(35, 8%, 85%)"] + ] + }, + "fill-opacity": {"base": 1, "stops": [[15.5, 0], [16, 1]]}, + "fill-outline-color": "hsl(35, 6%, 79%)" + } + }, + { + "id": "tunnel-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "tunnel-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "tunnel-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3], + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3], + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-dasharray": [3, 3], + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-dasharray": [3, 3], + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(230, 19%, 75%)" + } + }, + { + "id": "tunnel-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "tunnel"], ["==", "type", "trunk"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": 1, + "line-dasharray": [3, 3] + } + }, + { + "id": "tunnel-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "tunnel-path", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "tunnel-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "tunnel"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "tunnel-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 77%, 78%)", + "line-opacity": 1, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 78%)", + "line-opacity": 1, + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "tunnel-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [1, 0] + } + }, + { + "id": "tunnel-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-street", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "tunnel-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [1, 0], + "line-blur": 0 + } + }, + { + "id": "tunnel-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [1, 0], + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "tunnel-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "trunk"], ["==", "structure", "tunnel"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 77%, 78%)" + } + }, + { + "id": "tunnel-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "tunnel"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-dasharray": [1, 0], + "line-opacity": 1, + "line-color": "hsl(26, 100%, 78%)", + "line-blur": 0 + } + }, + { + "id": "tunnel-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855769305.6016"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + ["==", "structure", "tunnel"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "ferry"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(205, 73%, 63%)"], + [17, "hsl(230, 73%, 63%)"] + ] + }, + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [[12, [1, 0]], [13, [12, 4]]] + } + } + }, + { + "id": "ferry_auto", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "type", "ferry_auto"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [15, "hsl(205, 73%, 63%)"], + [17, "hsl(230, 73%, 63%)"] + ] + }, + "line-opacity": 1, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "road-path-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["!in", "type", "crossing", "sidewalk", "steps"], + ["==", "class", "path"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "road-steps-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "steps"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 2], [17, 4.6], [18, 7]] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [1, 0], + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "road-sidewalk-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "type", "crossing", "sidewalk"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 0.75]]} + } + }, + { + "id": "turning-features-outline", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "class", "turning_circle", "turning_loop"] + ], + "layout": { + "icon-image": "turning-circle-outline", + "icon-size": { + "base": 1.5, + "stops": [[14, 0.122], [18, 0.969], [20, 1]] + }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "road-pedestrian-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "road-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11, 0], [11.25, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "road-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]} + } + }, + { + "id": "road-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]} + } + }, + { + "id": "road-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": {"base": 1, "stops": [[9.99, 0], [10, 1]]} + } + }, + { + "id": "road-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "road-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "road-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "trunk"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-opacity": {"base": 1, "stops": [[6, 0], [6.1, 1]]} + } + }, + { + "id": "road-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "road-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "road-sidewalks", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "type", "crossing", "sidewalk"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]} + } + }, + { + "id": "road-path", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["!in", "type", "crossing", "sidewalk", "steps"], + ["==", "class", "path"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "road-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "steps"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "road-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)", + "line-opacity": 1 + } + }, + { + "id": "road-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)", + "line-opacity": 1 + } + }, + { + "id": "road-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "road-pedestrian-polygon-fill", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["==", "structure", "none"], + ["in", "class", "path", "pedestrian"] + ] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [16, "hsl(230, 16%, 94%)"], + [16.25, "hsl(230, 50%, 98%)"] + ] + }, + "fill-outline-color": "hsl(230, 26%, 88%)", + "fill-opacity": 1 + } + }, + { + "id": "road-pedestrian-polygon-pattern", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["==", "structure", "none"], + ["in", "class", "path", "pedestrian"] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "hsl(35, 10%, 83%)", + "fill-pattern": "pedestrian-polygon", + "fill-opacity": {"base": 1, "stops": [[16, 0], [16.25, 1]]} + } + }, + { + "id": "road-polygon", + "type": "fill", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + ["==", "$type", "Polygon"], + [ + "all", + ["!in", "class", "motorway", "path", "pedestrian", "trunk"], + ["!in", "structure", "bridge", "tunnel"] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "#d6d9e6" + } + }, + { + "id": "road-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "road-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "none"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-street", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "class", "street"], ["==", "structure", "none"]] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "road-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": { + "base": 1, + "stops": [[5, "hsl(35, 32%, 91%)"], [8, "hsl(0, 0%, 100%)"]] + }, + "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]} + } + }, + { + "id": "road-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [[5, "hsl(35, 32%, 91%)"], [7, "hsl(0, 0%, 100%)"]] + }, + "line-opacity": 1 + } + }, + { + "id": "road-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["==", "oneway", "true"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["!in", "structure", "bridge", "tunnel"], + ["==", "oneway", "true"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "road-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "trunk"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [ + [6, "hsl(0, 0%, 100%)"], + [6.1, "hsl(46, 80%, 60%)"], + [9, "hsl(46, 85%, 67%)"] + ] + } + } + }, + { + "id": "road-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["==", "class", "motorway"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": { + "base": 1, + "stops": [ + [8, "hsl(26, 87%, 62%)"], + [9, "hsl(26, 100%, 68%)"] + ] + } + } + }, + { + "id": "road-rail", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "road-rail-tracks", + "type": "line", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]}, + "line-dasharray": [0.1, 15], + "line-opacity": {"base": 1, "stops": [[13.75, 0], [14, 1]]} + } + }, + { + "id": "level-crossings", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "Point"], + ["==", "class", "level_crossing"] + ], + "layout": { + "icon-size": 1, + "icon-image": "level-crossing", + "icon-allow-overlap": true + }, + "paint": {} + }, + { + "id": "road-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "structure", "bridge", "tunnel"], + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {} + }, + { + "id": "turning-features", + "type": "symbol", + "metadata": {"mapbox:group": "1444855786460.0557"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "class", "turning_circle", "turning_loop"] + ], + "layout": { + "icon-image": "turning-circle", + "icon-size": {"base": 1.5, "stops": [[14, 0.095], [18, 1]]}, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {} + }, + { + "id": "bridge-path-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 2], [18, 7]]}, + "line-dasharray": [1, 0], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": {"base": 1, "stops": [[15, 0], [15.25, 1]]} + } + }, + { + "id": "bridge-steps-bg", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 2], [17, 4.6], [18, 7]] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [1, 0], + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 0.75]]} + } + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 2], [18, 14.5]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-street-low", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "bridge-street_limited-low", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [[11.5, 0], [12, 1], [14, 1], [14.01, 0]] + } + } + }, + { + "id": "bridge-service-link-track-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "bridge"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]} + } + }, + { + "id": "bridge-street_limited-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + } + } + }, + { + "id": "bridge-street-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-gap-width": { + "base": 1.5, + "stops": [[13, 0], [14, 2], [18, 18]] + } + } + }, + { + "id": "bridge-secondary-tertiary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "secondary", "tertiary"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.2, "stops": [[10, 0.75], [18, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-translate": [0, 0] + } + }, + { + "id": "bridge-primary-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "primary"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-translate": [0, 0] + } + }, + { + "id": "bridge-trunk_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "bridge-motorway_link-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-motorway-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-construction", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "construction"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "line-dasharray": { + "base": 1, + "stops": [ + [14, [0.4, 0.8]], + [15, [0.3, 0.6]], + [16, [0.2, 0.3]], + [17, [0.2, 0.25]], + [18, [0.15, 0.15]] + ] + } + } + }, + { + "id": "bridge-path", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "steps"], + ["==", "class", "path"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[15, 1], [18, 4]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [1, 0.5]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "bridge-steps", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + ["all", ["==", "structure", "bridge"], ["==", "type", "steps"]] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[15, 1], [16, 1.6], [18, 6]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [14, [1, 0]], + [15, [1.75, 1]], + [16, [1, 0.75]], + [17, [0.3, 0.3]] + ] + }, + "line-opacity": {"base": 1, "stops": [[14, 0], [14.25, 1]]} + } + }, + { + "id": "bridge-trunk_link", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-pedestrian", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "pedestrian"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [[14, [1, 0]], [15, [1.5, 0.4]], [16, [1, 0.2]]] + } + } + }, + { + "id": "bridge-service-link-track", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!=", "type", "trunk_link"], + ["==", "structure", "bridge"], + ["in", "class", "link", "service", "track"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[14, 0.5], [18, 12]]}, + "line-color": "hsl(0, 0%, 100%)" + } + }, + { + "id": "bridge-street_limited", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street_limited"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-street", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "street"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12.5, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]} + } + }, + { + "id": "bridge-secondary-tertiary", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "type", "secondary", "tertiary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[8.5, 0.5], [10, 0.75], [18, 26]] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": {"base": 1.2, "stops": [[5, 0], [5.5, 1]]} + } + }, + { + "id": "bridge-primary", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "primary"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1 + } + }, + { + "id": "bridge-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[17, "oneway-small"], [18, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-oneway-arrows-blue-major", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [[16, "oneway-small"], [17, "oneway-large"]] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "bridge-trunk", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "trunk"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["!in", "layer", 2, 3, 4, 5], + ["==", "class", "motorway"], + ["==", "structure", "bridge"] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-rail", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "bridge-rail-tracks", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["in", "class", "major_rail", "minor_rail"] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": { + "stops": [ + [13, "hsl(50, 17%, 82%)"], + [16, "hsl(230, 10%, 74%)"] + ] + }, + "line-width": {"base": 1.5, "stops": [[14, 4], [20, 8]]}, + "line-dasharray": [0.1, 15], + "line-opacity": {"base": 1, "stops": [[13.75, 0], [20, 1]]} + } + }, + { + "id": "bridge-trunk_link-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": {"base": 1, "stops": [[10.99, 0], [11, 1]]} + } + }, + { + "id": "bridge-motorway_link-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[12, 0.75], [20, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-opacity": 1 + } + }, + { + "id": "bridge-trunk-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-motorway-2-case", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[10, 1], [16, 2]]}, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]} + } + }, + { + "id": "bridge-trunk_link-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "structure", "bridge"], + ["==", "type", "trunk_link"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway_link-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway_link"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": { + "base": 1.5, + "stops": [[12, 0.5], [14, 2], [18, 18]] + }, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-trunk-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "trunk"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(46, 85%, 67%)" + } + }, + { + "id": "bridge-motorway-2", + "type": "line", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + ["==", "class", "motorway"], + ["==", "structure", "bridge"], + [">=", "layer", 2] + ] + ], + "layout": {"line-cap": "round", "line-join": "round"}, + "paint": { + "line-width": {"base": 1.5, "stops": [[5, 0.75], [18, 32]]}, + "line-color": "hsl(26, 100%, 68%)" + } + }, + { + "id": "bridge-oneway-arrows-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444855799204.86"}, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + ["==", "oneway", "true"], + ["==", "structure", "bridge"], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [16, "oneway-white-small"], + [17, "oneway-white-large"] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {} + }, + { + "id": "aerialway", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "class", "aerialway"] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-color": "hsl(230, 10%, 74%)", + "line-width": {"base": 1.5, "stops": [[14, 0.5], [20, 1]]} + } + }, + { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]], + "layout": {"line-join": "bevel"}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [8, "hsl(35, 12%, 89%)"], + [16, "hsl(230, 49%, 90%)"] + ] + }, + "line-width": {"base": 1, "stops": [[7, 3.75], [12, 5.5]]}, + "line-opacity": {"base": 1, "stops": [[7, 0], [8, 0.75]]}, + "line-dasharray": [1, 0], + "line-translate": [0, 0], + "line-blur": {"base": 1, "stops": [[3, 0], [8, 3]]} + } + }, + { + "id": "admin-2-boundaries-bg", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": ["all", ["==", "admin_level", 2], ["==", "maritime", 0]], + "layout": {"line-join": "miter"}, + "paint": { + "line-width": {"base": 1, "stops": [[3, 3.5], [10, 8]]}, + "line-color": { + "base": 1, + "stops": [ + [6, "hsl(35, 12%, 89%)"], + [8, "hsl(230, 49%, 90%)"] + ] + }, + "line-opacity": {"base": 1, "stops": [[3, 0], [4, 0.5]]}, + "line-translate": [0, 0], + "line-blur": {"base": 1, "stops": [[3, 0], [10, 2]]} + } + }, + { + "id": "admin-3-4-boundaries", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "filter": ["all", ["==", "maritime", 0], [">=", "admin_level", 3]], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-dasharray": { + "base": 1, + "stops": [[6, [2, 0]], [7, [2, 2, 6, 2]]] + }, + "line-width": {"base": 1, "stops": [[7, 0.75], [12, 1.5]]}, + "line-opacity": {"base": 1, "stops": [[2, 0], [3, 1]]}, + "line-color": { + "base": 1, + "stops": [ + [3, "hsl(230, 14%, 77%)"], + [7, "hsl(230, 8%, 62%)"] + ] + } + } + }, + { + "id": "admin-2-boundaries", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", 0], + ["==", "maritime", 0] + ], + "layout": {"line-join": "round", "line-cap": "round"}, + "paint": { + "line-color": "hsl(230, 8%, 51%)", + "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]} + } + }, + { + "id": "admin-2-boundaries-dispute", + "type": "line", + "metadata": {"mapbox:group": "1444934295202.7542"}, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + ["==", "admin_level", 2], + ["==", "disputed", 1], + ["==", "maritime", 0] + ], + "layout": {"line-join": "round"}, + "paint": { + "line-dasharray": [1.5, 1.5], + "line-color": "hsl(230, 8%, 51%)", + "line-width": {"base": 1, "stops": [[3, 0.5], [10, 2]]} + } + }, + { + "id": "housenum-label", + "type": "symbol", + "source": "composite", + "source-layer": "housenum_label", + "minzoom": 17, + "layout": { + "text-field": "{house_num}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-padding": 4, + "text-max-width": 7, + "text-size": 9.5 + }, + "paint": { + "text-color": "hsl(35, 2%, 69%)", + "text-halo-color": "hsl(35, 8%, 85%)", + "text-halo-width": 0.5, + "text-halo-blur": 0 + } + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "composite", + "source-layer": "waterway_label", + "minzoom": 12, + "filter": ["in", "class", "canal", "river"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-max-angle": 30, + "text-size": {"base": 1, "stops": [[13, 12], [18, 16]]} + }, + "paint": { + "text-halo-width": 0.5, + "text-halo-color": "hsl(196, 80%, 70%)", + "text-color": "hsl(230, 48%, 44%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l15", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 17, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 4], + [">=", "localrank", 15] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank4-l1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["<=", "localrank", 14], + ["==", "scalerank", 4] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks_scalerank4", + "type": "symbol", + "metadata": {"mapbox:group": "1444933456003.5437"}, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + ["==", "scalerank", 4], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank3", + "type": "symbol", + "metadata": {"mapbox:group": "1444933372896.5967"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 3] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank3", + "type": "symbol", + "metadata": {"mapbox:group": "1444933372896.5967"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["==", "scalerank", 3], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "road-label-small", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "class", + "golf", + "link", + "motorway", + "pedestrian", + "primary", + "secondary", + "street", + "street_limited", + "tertiary", + "trunk" + ], + ["==", "$type", "LineString"] + ], + "layout": { + "text-size": {"base": 1, "stops": [[15, 10], [20, 13]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-halo-blur": 1 + } + }, + { + "id": "road-label-medium", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "minzoom": 11, + "filter": [ + "all", + ["==", "$type", "LineString"], + [ + "in", + "class", + "link", + "pedestrian", + "street", + "street_limited" + ] + ], + "layout": { + "text-size": {"base": 1, "stops": [[11, 10], [20, 14]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "road-label-large", + "type": "symbol", + "metadata": {"mapbox:group": "1444933721429.3076"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + "layout": { + "text-size": {"base": 1, "stops": [[9, 10], [20, 16]]}, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + } + }, + { + "id": "road-shields-black", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "!in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ], + ["<=", "reflen", 6] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]}, + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 7%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "road-shields-white", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + ["<=", "reflen", 6], + [ + "in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": {"base": 1, "stops": [[11, 150], [14, 200]]}, + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "symbol-placement": { + "base": 1, + "stops": [[10, "point"], [11, "line"]] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + } + }, + { + "id": "motorway-junction", + "type": "symbol", + "metadata": {"mapbox:group": "1444933575858.6992"}, + "source": "composite", + "source-layer": "motorway_junction", + "minzoom": 14, + "filter": ["all", ["<=", "reflen", 9], [">", "reflen", 0]], + "layout": { + "text-field": "{ref}", + "text-size": 9, + "icon-image": "motorway-exit-{reflen}", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"] + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "text-translate": [0, 0] + } + }, + { + "id": "poi-scalerank2", + "type": "symbol", + "metadata": {"mapbox:group": "1444933358918.2366"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["==", "scalerank", 2] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]}, + "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank2", + "type": "symbol", + "metadata": {"mapbox:group": "1444933358918.2366"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["==", "scalerank", 2], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[14, 11], [20, 14]]}, + "icon-image": {"stops": [[14, "{maki}-11"], [15, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "rail-label", + "type": "symbol", + "source": "composite", + "source-layer": "rail_station_label", + "minzoom": 12, + "filter": ["!=", "maki", "entrance"], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[16, 11], [20, 13]]}, + "icon-image": "{network}", + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-offset": [0, 0.85], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "base": 1, + "stops": [[0, ""], [13, "{name_en}"]] + }, + "text-letter-spacing": 0.01, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": {"base": 1, "stops": [[13.99, 0], [14, 1]]}, + "text-halo-blur": 0.5 + } + }, + { + "id": "water-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444933808272.805"}, + "source": "composite", + "source-layer": "water_label", + "minzoom": 15, + "filter": ["<=", "area", 10000], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[16, 13], [20, 16]]} + }, + "paint": {"text-color": "hsl(230, 48%, 44%)"} + }, + { + "id": "water-label", + "type": "symbol", + "metadata": {"mapbox:group": "1444933808272.805"}, + "source": "composite", + "source-layer": "water_label", + "minzoom": 5, + "filter": [">", "area", 10000], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[13, 13], [18, 18]]} + }, + "paint": {"text-color": "hsl(230, 48%, 44%)"} + }, + { + "id": "place-residential", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 18, + "filter": [ + "all", + ["all", ["<=", "localrank", 10], ["==", "type", "residential"]], + ["in", "$type", "LineString", "Point", "Polygon"] + ], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-parks-scalerank1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933322393.2852"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + ["<=", "scalerank", 1], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "poi-scalerank1", + "type": "symbol", + "metadata": {"mapbox:group": "1444933322393.2852"}, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + ["<=", "scalerank", 1] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 11], [18, 14]]}, + "icon-image": {"stops": [[13, "{maki}-11"], [14, "{maki}-15"]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.65], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "airport-label", + "type": "symbol", + "source": "composite", + "source-layer": "airport_label", + "minzoom": 9, + "filter": ["<=", "scalerank", 2], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[10, 12], [18, 18]]}, + "icon-image": {"stops": [[12, "{maki}-11"], [13, "{maki}-15"]]}, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0.75], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": {"stops": [[11, "{ref}"], [12, "{name_en}"]]}, + "text-letter-spacing": 0.01, + "text-max-width": 9 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + } + }, + { + "id": "place-islet-archipelago-aboriginal", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ + "in", + "type", + "aboriginal_lands", + "archipelago", + "islet" + ], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-neighbourhood", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "neighbourhood"], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 3, + "text-size": {"base": 1, "stops": [[12, 11], [16, 16]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-suburb", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "suburb"], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3, + "text-size": {"base": 1, "stops": [[11, 11], [15, 18]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + } + }, + { + "id": "place-hamlet", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": ["==", "type", "hamlet"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[12, 11.5], [15, 16]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 8, + "maxzoom": 15, + "filter": ["==", "type", "village"], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[10, 11.5], [16, 18]]} + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + } + }, + { + "id": "place-town", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 6, + "maxzoom": 15, + "filter": ["==", "type", "town"], + "layout": { + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 11, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [ + 12, + ["DIN Offc Pro Medium", "Arial Unicode MS Regular"] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7, [0, -0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 1, "stops": [[7, 11.5], [15, 20]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-island", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": ["==", "type", "island"], + "layout": { + "text-line-height": 1.2, + "text-size": {"base": 1, "stops": [[10, 11], [18, 16]]}, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular", + "Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [0, 0], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "place-city-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["!in", "scalerank", 0, 1, 2, 3, 4, 5], + ["==", "type", "city"] + ], + "layout": { + "text-size": {"base": 1, "stops": [[6, 12], [14, 22]]}, + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.2]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-city-md-s", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["==", "type", "city"], + ["in", "ldir", "E", "S", "SE", "SW"], + ["in", "scalerank", 3, 4, 5] + ], + "layout": { + "text-field": "{name_en}", + "icon-image": "dot-10", + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.1]], [8, [0, 0]]] + }, + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]} + }, + "paint": { + "text-halo-width": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]} + } + }, + { + "id": "place-city-md-n", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + ["==", "type", "city"], + ["in", "ldir", "N", "NE", "NW", "W"], + ["in", "scalerank", 3, 4, 5] + ], + "layout": { + "icon-image": "dot-10", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[5, 12], [12, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-s", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + ["<=", "scalerank", 2], + ["==", "type", "city"], + ["in", "ldir", "E", "S", "SE", "SW"] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, 0.15]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "top"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "place-city-lg-n", + "type": "symbol", + "metadata": {"mapbox:group": "1444862510685.128"}, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + ["<=", "scalerank", 2], + ["==", "type", "city"], + ["in", "ldir", "N", "NE", "NW", "W"] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + ["DIN Offc Pro Regular", "Arial Unicode MS Regular"] + ], + [8, ["DIN Offc Pro Medium", "Arial Unicode MS Regular"]] + ] + }, + "text-offset": { + "base": 1, + "stops": [[7.99, [0, -0.25]], [8, [0, 0]]] + }, + "text-anchor": { + "base": 1, + "stops": [[7, "bottom"], [8, "center"]] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": {"base": 0.9, "stops": [[4, 12], [10, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-opacity": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": {"base": 1, "stops": [[7.99, 1], [8, 0]]}, + "text-halo-blur": 1 + } + }, + { + "id": "marine-label-sm-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ + "all", + ["==", "$type", "LineString"], + [">=", "labelrank", 4] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]}, + "symbol-spacing": {"base": 1, "stops": [[4, 100], [6, 400]]}, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-sm-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": ["all", ["==", "$type", "Point"], [">=", "labelrank", 4]], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[3, 12], [6, 16]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-md-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["in", "labelrank", 2, 3] + ], + "layout": { + "text-line-height": 1.1, + "text-size": {"base": 1.1, "stops": [[2, 12], [5, 20]]}, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-md-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + ["==", "$type", "Point"], + ["in", "labelrank", 2, 3] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1.1, "stops": [[2, 14], [5, 20]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-lg-ln", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ + "all", + ["==", "$type", "LineString"], + ["==", "labelrank", 1] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "marine-label-lg-pt", + "type": "symbol", + "metadata": {"mapbox:group": "1444856087950.3635"}, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": ["all", ["==", "$type", "Point"], ["==", "labelrank", 1]], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 14], [4, 30]]} + }, + "paint": {"text-color": "hsl(205, 83%, 88%)"} + }, + { + "id": "state-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 9, + "filter": ["<", "area", 20000], + "layout": { + "text-size": {"base": 1, "stops": [[6, 10], [9, 14]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [6, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-md", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 8, + "filter": ["all", ["<", "area", 80000], [">=", "area", 20000]], + "layout": { + "text-size": {"base": 1, "stops": [[5, 10], [8, 16]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [5, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "state-label-lg", + "type": "symbol", + "metadata": {"mapbox:group": "1444856151690.9143"}, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 7, + "filter": [">=", "area", 80000], + "layout": { + "text-size": {"base": 1, "stops": [[4, 10], [7, 18]]}, + "text-transform": "uppercase", + "text-font": ["DIN Offc Pro Bold", "Arial Unicode MS Bold"], + "text-padding": 1, + "text-field": { + "base": 1, + "stops": [[0, "{abbr}"], [4, "{name_en}"]] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + } + }, + { + "id": "country-label-sm", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 10, + "filter": [">=", "scalerank", 5], + "layout": { + "text-field": "{name_en}", + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 0.9, "stops": [[5, 14], [9, 22]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-md", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 8, + "filter": ["in", "scalerank", 3, 4], + "layout": { + "text-field": { + "base": 1, + "stops": [[0, "{code}"], [2, "{name_en}"]] + }, + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[3, 10], [8, 24]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + }, + { + "id": "country-label-lg", + "type": "symbol", + "metadata": {"mapbox:group": "1444856144497.7825"}, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 7, + "filter": ["in", "scalerank", 1, 2], + "layout": { + "text-field": "{name_en}", + "text-max-width": {"base": 1, "stops": [[0, 5], [3, 6]]}, + "text-font": [ + "DIN Offc Pro Medium", + "Arial Unicode MS Regular" + ], + "text-size": {"base": 1, "stops": [[1, 10], [6, 24]]} + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [2, "rgba(255,255,255,0.75)"], + [3, "hsl(0, 0%, 100%)"] + ] + }, + "text-halo-width": 1.25 + } + } + ], + "created": "2018-10-22T14:13:43.210Z", + "id": "cjnkdt02b0b2p2ss40skwpvs1", + "modified": "2018-10-22T14:14:35.211Z", + "owner": "lukaspaczos", + "visibility": "public", + "draft": false +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt new file mode 100644 index 0000000000..ea48bdc00f --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationApplication.kt @@ -0,0 +1,10 @@ +package com.mapbox.mapboxsdk + +import com.mapbox.mapboxsdk.testapp.MapboxApplication + +class InstrumentationApplication : MapboxApplication() { + override fun initializeLeakCanary(): Boolean { + // do not initialize leak canary during instrumentation tests + return true + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt new file mode 100644 index 0000000000..6873b33262 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/InstrumentationRunner.kt @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk + +import android.app.Application +import android.content.Context +import android.support.test.runner.AndroidJUnitRunner + +class InstrumentationRunner : AndroidJUnitRunner() { + override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application { + return super.newApplication(cl, InstrumentationApplication::class.java.name, context) + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt new file mode 100644 index 0000000000..aeb8863790 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/BaseIntegrationTest.kt @@ -0,0 +1,39 @@ +package com.mapbox.mapboxsdk.integration + +import android.content.Context +import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK +import android.support.test.InstrumentationRegistry +import android.support.test.uiautomator.* +import org.junit.Before + +const val TIMEOUT_UI_SEARCH_WAIT = 5000L + +abstract class BaseIntegrationTest { + + protected lateinit var device: UiDevice + + @Before + open fun beforeTest() { + device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + } +} + +/** + * Launches an activity with FLAG_ACTIVITY_NEW_TASK. + * <p> + * To resume an activity, you need to add a single instance launchmode to your manifest configuration. + * <p> + */ +fun UiDevice.launchActivity(context: Context, clazz: Class<*>) { + val applicationPackage = InstrumentationRegistry.getTargetContext().packageName + val intent = Intent(context, clazz) + intent.addFlags(FLAG_ACTIVITY_NEW_TASK) + InstrumentationRegistry.getContext().startActivity(intent) + wait(Until.hasObject(By.pkg(applicationPackage).depth(0)), TIMEOUT_UI_SEARCH_WAIT) +} + +fun UiDevice.scrollRecyclerViewTo(recycleItem: String) { + val appView = UiScrollable(UiSelector().scrollable(true)) + appView.scrollIntoView(UiSelector().text(recycleItem)) +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt new file mode 100644 index 0000000000..b0f6436bdd --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/FragmentBackStackTest.kt @@ -0,0 +1,52 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.support.test.uiautomator.By +import android.support.test.uiautomator.SearchCondition +import android.support.test.uiautomator.UiSelector +import android.support.test.uiautomator.Until +import com.mapbox.mapboxsdk.testapp.R +import com.mapbox.mapboxsdk.testapp.activity.fragment.FragmentBackStackActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import kotlinx.android.synthetic.main.activity_backstack_fragment.view.* +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates MapFragment integration on the backstack + */ +@RunWith(AndroidJUnit4::class) +class FragmentBackStackTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<FragmentBackStackActivity> = ActivityTestRule(FragmentBackStackActivity::class.java) + + @Test + @LargeTest + fun backPressedOnBackStackResumed() { + device.waitForIdle() + clickReplaceFragmentButton() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity.applicationContext, FragmentBackStackActivity::class.java) + backPressBackStack() + device.waitForIdle() + } + + private fun clickReplaceFragmentButton() { + device.findObject(UiSelector().description(textDescription)).click() + } + + private fun backPressBackStack() { + device.pressBack() // pops fragment, showing map + device.pressBack() // finish activity + } + + private companion object { + const val textDescription = "btn_change_fragment" + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt new file mode 100644 index 0000000000..f22b5f7c9d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReopenTest.kt @@ -0,0 +1,30 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + + +/** + * Regression test that validates reopening an Activity with a GLSurfaceView + */ +@RunWith(AndroidJUnit4::class) +class GLSurfaceViewReopenTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java) + + @Test + @LargeTest + fun reopenSimpleMapActivity() { + device.waitForIdle() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity, SimpleMapActivity::class.java) + device.waitForIdle() + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt new file mode 100644 index 0000000000..945fac677e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/GLSurfaceViewReuseTest.kt @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates if a GLSurfaceView surface can be recreated without crashing. + */ +@RunWith(AndroidJUnit4::class) +class GLSurfaceViewReuseTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<GLSurfaceRecyclerViewActivity> = ActivityTestRule(GLSurfaceRecyclerViewActivity::class.java) + + @Test + @LargeTest + fun scrollRecyclerView() { + device.waitForIdle() + device.scrollRecyclerViewTo("Twenty-one") + device.waitForIdle() + device.scrollRecyclerViewTo("One") + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt new file mode 100644 index 0000000000..941b7ea8dc --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/OrientationChangeTest.kt @@ -0,0 +1,34 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class OrientationChangeTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<SimpleMapActivity> = ActivityTestRule(SimpleMapActivity::class.java) + + @Test + @LargeTest + fun rotateSimpleMap() { + device.setOrientationLeft() + device.waitForIdle() + device.setOrientationNatural() + device.waitForIdle() + device.setOrientationRight() + device.waitForIdle() + device.setOrientationNatural() + device.setOrientationLeft() + device.setOrientationNatural() + device.setOrientationRight() + device.setOrientationNatural() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt new file mode 100644 index 0000000000..44da557904 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReopenTest.kt @@ -0,0 +1,33 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.SimpleMapActivity +import com.mapbox.mapboxsdk.testapp.activity.textureview.TextureViewDebugModeActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.Thread.sleep + +/** + * Regression test that validates reopening an Activity with a TextureView + */ +@RunWith(AndroidJUnit4::class) +class TextureViewReopenTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<TextureViewDebugModeActivity> = ActivityTestRule(TextureViewDebugModeActivity::class.java) + + @Test + @LargeTest + fun reopenTextureViewDebugActivity() { + device.waitForIdle() + device.pressHome() + device.waitForIdle() + device.launchActivity(activityRule.activity, TextureViewDebugModeActivity::class.java) + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt new file mode 100644 index 0000000000..5c3d66c462 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/TextureViewReuseTest.kt @@ -0,0 +1,31 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.TextureRecyclerViewActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates if a GLSurfaceView surface can be recreated without crashing. + */ +@RunWith(AndroidJUnit4::class) +class TextureViewReuseTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<TextureRecyclerViewActivity> = ActivityTestRule(TextureRecyclerViewActivity::class.java) + + @Test + @LargeTest + fun scrollRecyclerView() { + device.waitForIdle() + device.scrollRecyclerViewTo("Twenty-one") + device.waitForIdle() + device.scrollRecyclerViewTo("One") + device.waitForIdle() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt new file mode 100644 index 0000000000..b918801296 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/integration/ViewPagerScrollTest.kt @@ -0,0 +1,38 @@ +package com.mapbox.mapboxsdk.integration + +import android.support.test.filters.LargeTest +import android.support.test.rule.ActivityTestRule +import android.support.test.runner.AndroidJUnit4 +import android.support.test.uiautomator.UiSelector +import com.mapbox.mapboxsdk.testapp.activity.fragment.ViewPagerActivity +import com.mapbox.mapboxsdk.testapp.activity.maplayout.GLSurfaceRecyclerViewActivity +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Regression test that validates MapFragment integration with a ViewPager + */ +@RunWith(AndroidJUnit4::class) +class ViewPagerScrollTest : BaseIntegrationTest() { + + @get:Rule + var activityRule: ActivityTestRule<ViewPagerActivity> = ActivityTestRule(ViewPagerActivity::class.java) + + @Test + @LargeTest + fun scrollViewPager() { + for (i in 1..4) { + clickTab(i) + } + + for (i in 3 downTo 0) { + clickTab(i) + } + } + + private fun clickTab(index: Int) { + device.findObject(UiSelector().text("Page $index")).click() + } +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt index dde03d8a14..f9827c767e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationComponentTest.kt @@ -82,7 +82,7 @@ class LocationComponentTest : EspressoTest() { val locationEngine = component.locationEngine assertThat(locationEngine, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } @@ -118,7 +118,7 @@ class LocationComponentTest : EspressoTest() { assertThat(locationEngine, notNullValue()) assertThat(componentOptions, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(componentOptions?.accuracyAlpha(), `is`(.5f)) assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE)) } @@ -157,7 +157,7 @@ class LocationComponentTest : EspressoTest() { assertThat(locationEngine, nullValue()) assertThat(componentOptions, notNullValue()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(componentOptions?.accuracyAlpha(), `is`(.5f)) assertThat(componentOptions?.accuracyColor(), `is`(Color.BLUE)) } @@ -205,7 +205,7 @@ class LocationComponentTest : EspressoTest() { // Force the first location update component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) // Check if the puck is visible assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false)) @@ -240,7 +240,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(300) // waiting for stale state mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature -> @@ -287,7 +287,7 @@ class LocationComponentTest : EspressoTest() { } component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val feature = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0] assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(false)) @@ -329,7 +329,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.addImageFromDrawable("custom-foreground-bitmap", it) mapboxMap.addImageFromDrawable("custom-gps-bitmap", it) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) @@ -360,13 +360,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) component.applyStyle(LocationComponentOptions.builder(context).build()) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)) } @@ -395,13 +395,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val foregroundId = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON) assertThat(foregroundId, `is`(equalTo("custom-gps-bitmap"))) component.renderMode = RenderMode.NORMAL - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(FOREGROUND_ICON, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getStringProperty(PROPERTY_FOREGROUND_ICON)) } @@ -430,14 +430,14 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(250) // engaging stale state assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(false)) @@ -461,13 +461,13 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(false)) assertThat(mapboxMap.isLayerVisible(ACCURACY_LAYER), `is`(true)) @@ -499,7 +499,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.querySourceFeatures(LOCATION_SOURCE).also { feature -> feature.forEach { @@ -526,7 +526,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertThat(component.locationEngine, nullValue()) @@ -550,14 +550,14 @@ class LocationComponentTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) assertEquals(point.longitude(), location.longitude, 0.1) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) } } @@ -580,7 +580,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = false mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) component.isLocationComponentEnabled = true - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) } @@ -675,7 +675,7 @@ class LocationComponentTest : EspressoTest() { component.onStart() mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -695,7 +695,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.setStyle(Style.Builder().fromUrl(Style.DARK)) component.onStop() component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -714,7 +714,7 @@ class LocationComponentTest : EspressoTest() { component.isLocationComponentEnabled = true component.onStop() component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE).isEmpty(), `is`(true)) } @@ -736,7 +736,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.forceLocationUpdate(location) component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) @@ -760,9 +760,9 @@ class LocationComponentTest : EspressoTest() { component.forceLocationUpdate(location) mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) component.onStop() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.onStart() - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) val point: Point = mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].geometry() as Point assertEquals(point.latitude(), location.latitude, 0.1) @@ -797,7 +797,7 @@ class LocationComponentTest : EspressoTest() { component.applyStyle(options) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -823,7 +823,7 @@ class LocationComponentTest : EspressoTest() { component.forceLocationUpdate(location) } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -839,7 +839,7 @@ class LocationComponentTest : EspressoTest() { override fun onLocationComponentAction(component: LocationComponent, mapboxMap: MapboxMap, style: Style, uiController: UiController, context: Context) { styleChangeIdlingResource.waitForStyle(mapboxMap, MAPBOX_HEAVY_STYLE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) locationComponentActivationOptions = LocationComponentActivationOptions .builder(context, mapboxMap.style!!) @@ -878,13 +878,13 @@ class LocationComponentTest : EspressoTest() { component.renderMode = RenderMode.GPS location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f) location.bearing = 92f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish assertEquals(92.0f, mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getNumberProperty(PROPERTY_GPS_BEARING).toFloat(), 0.1f) } @@ -906,7 +906,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING_GPS location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -917,7 +917,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) // Waiting for the animation to finish assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -945,7 +945,7 @@ class LocationComponentTest : EspressoTest() { location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(77.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -956,7 +956,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(92.0, mapboxMap.cameraPosition.bearing, 0.1) @@ -985,7 +985,7 @@ class LocationComponentTest : EspressoTest() { location.bearing = 77f component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1) @@ -996,7 +996,7 @@ class LocationComponentTest : EspressoTest() { location.latitude = 30.0 location.longitude = 35.0 component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(bearing, mapboxMap.cameraPosition.bearing, 0.1) @@ -1021,7 +1021,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.cameraMode = CameraMode.NONE component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.uiSettings.focalPoint, nullValue()) } @@ -1044,7 +1044,7 @@ class LocationComponentTest : EspressoTest() { val zoom = mapboxMap.cameraPosition.zoom component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1066,7 +1066,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(10.0, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1091,7 +1091,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) component.cameraMode = CameraMode.NONE uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) } @@ -1117,7 +1117,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.zoomWhileTracking(10.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(zoom, mapboxMap.cameraPosition.zoom, 0.1) } @@ -1142,7 +1142,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) component.cancelZoomWhileTrackingAnimation() uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_ZOOM_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(15.0 / 2.0, mapboxMap.cameraPosition.zoom, 3.0) } @@ -1165,7 +1165,7 @@ class LocationComponentTest : EspressoTest() { val tilt = mapboxMap.cameraPosition.tilt component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1187,7 +1187,7 @@ class LocationComponentTest : EspressoTest() { component.cameraMode = CameraMode.TRACKING component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(30.0, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1212,7 +1212,7 @@ class LocationComponentTest : EspressoTest() { uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) component.cameraMode = CameraMode.NONE uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION / 2) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(30.0 / 2.0, mapboxMap.cameraPosition.tilt, 3.0) } @@ -1237,7 +1237,7 @@ class LocationComponentTest : EspressoTest() { component.onStop() component.tiltWhileTracking(30.0) uiController.loopMainThreadForAtLeast(DEFAULT_TRACKING_TILT_ANIM_DURATION) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertEquals(tilt, mapboxMap.cameraPosition.tilt, 0.1) } @@ -1286,7 +1286,7 @@ class LocationComponentTest : EspressoTest() { mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(LatLng(51.0, 17.0))) mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(90.0)) component.isLocationComponentEnabled = true - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(MAX_ANIMATION_DURATION_MS) assertEquals(location.bearing.toDouble(), mapboxMap.cameraPosition.bearing, 0.1) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt index 37b3e8b802..fb450de527 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.kt @@ -75,7 +75,7 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.renderMode = RenderMode.NORMAL - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(style.getSource(LOCATION_SOURCE), notNullValue()) } @@ -99,7 +99,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -123,7 +123,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.COMPASS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -147,7 +147,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.renderMode = RenderMode.GPS component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(true)) assertThat(mapboxMap.isLayerVisible(BACKGROUND_LAYER), `is`(true)) @@ -171,7 +171,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.forceLocationUpdate(location) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.renderMode = RenderMode.GPS assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false)) @@ -197,7 +197,7 @@ class LocationLayerControllerTest : EspressoTest() { component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) // Check that all layers visibilities are set to none assertThat(mapboxMap.isLayerVisible(FOREGROUND_LAYER), `is`(false)) @@ -223,7 +223,7 @@ class LocationLayerControllerTest : EspressoTest() { component.renderMode = RenderMode.NORMAL component.forceLocationUpdate(location) styleChangeIdlingResource.waitForStyle(mapboxMap, Style.LIGHT) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(component.renderMode, `is`(equalTo(RenderMode.NORMAL))) @@ -254,13 +254,13 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true component.applyStyle(LocationComponentOptions.builder(context).staleStateTimeout(100).build()) component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(150) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) mapboxMap.setStyle(Style.Builder().fromUrl(Style.LIGHT)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.querySourceFeatures(LOCATION_SOURCE)[0].getBooleanProperty(PROPERTY_LOCATION_STALE), `is`(true)) } @@ -279,9 +279,9 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.isLocationComponentEnabled = false - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) val options = @@ -291,7 +291,7 @@ class LocationLayerControllerTest : EspressoTest() { .build() component.applyStyle(options) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(mapboxMap.queryRenderedFeatures(location, FOREGROUND_LAYER).isEmpty(), `is`(true)) } } @@ -338,7 +338,7 @@ class LocationLayerControllerTest : EspressoTest() { show = !show } - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) } } executeComponentTest(componentAction) @@ -359,7 +359,7 @@ class LocationLayerControllerTest : EspressoTest() { component.isLocationComponentEnabled = true mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(location), 16.0)) component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) uiController.loopMainThreadForAtLeast(ACCURACY_RADIUS_ANIMATION_DURATION) assertEquals(Utils.calculateZoomLevelRadius(mapboxMap, location) /*meters projected to radius on zoom 16*/, @@ -386,7 +386,7 @@ class LocationLayerControllerTest : EspressoTest() { val zoom = 16.0 mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(target, zoom), 300) uiController.loopMainThreadForAtLeast(300) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1 @@ -418,7 +418,7 @@ class LocationLayerControllerTest : EspressoTest() { val target = LatLng(location) val zoom = 16.0 mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(target, zoom)) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) assertThat(Math.abs(zoom - mapboxMap.cameraPosition.zoom) < 0.1 && Math.abs(target.latitude - mapboxMap.cameraPosition.target.latitude) < 0.1 @@ -445,7 +445,7 @@ class LocationLayerControllerTest : EspressoTest() { .build()) component.isLocationComponentEnabled = true component.forceLocationUpdate(location) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) component.applyStyle(LocationComponentOptions.builder(context).layerBelow("road-label").build()) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt deleted file mode 100644 index 98b251027f..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/GLSurfaceViewReopenTest.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.mapbox.mapboxsdk.maps - -import android.content.Intent -import android.support.test.InstrumentationRegistry -import android.support.test.filters.SdkSuppress -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.* -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.lang.Thread.sleep - -private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp" -private const val LAUNCH_TIMEOUT = 5000L - -@RunWith(AndroidJUnit4::class) -@SdkSuppress(minSdkVersion = 18) -class GLSurfaceViewReopenTest { - - private lateinit var device: UiDevice - - @Before - fun startSimpleMapActivityFromHomeScreen() { - // Initialize UiDevice instance - device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - // Start from the home screen - device.pressHome() - - // Wait for launcher - val launcherPackage: String = device.launcherPackageName - assertThat(launcherPackage, notNullValue()) - device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT) - - // Launch the app - val context = InstrumentationRegistry.getInstrumentation().context - val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply { - // Clear out any previous instances - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - context.startActivity(intent) - - // Wait for the app to appear - device.wait( - Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), - LAUNCH_TIMEOUT - ) - - // open SimpleMapActivity - device.findObject(UiSelector().text("Simple Map")).clickAndWaitForNewWindow() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - } - - @Test - fun reopenSimpleMapActivity() { - // return to home screen - device.pressHome() - - // press recents apps button - device.pressRecentApps() - - // click to reopen app - device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - sleep(LAUNCH_TIMEOUT) - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java index b56d267b81..c8737e2802 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxTest.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.maps; +import android.support.test.annotation.UiThreadTest; import android.support.test.runner.AndroidJUnit4; import com.mapbox.mapboxsdk.Mapbox; import org.junit.Test; @@ -16,6 +17,7 @@ public class MapboxTest { private static final String ACCESS_TOKEN_2 = "pk.0000000002"; @Test + @UiThreadTest public void testConnected() { assertTrue(Mapbox.isConnected()); @@ -31,6 +33,7 @@ public class MapboxTest { } @Test + @UiThreadTest public void setAccessToken() { String realToken = Mapbox.getAccessToken(); Mapbox.setAccessToken(ACCESS_TOKEN); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java deleted file mode 100644 index 14a2c3bdbf..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - -import com.mapbox.mapboxsdk.testapp.activity.BaseTest; -import com.mapbox.mapboxsdk.testapp.activity.camera.CameraAnimationTypeActivity; -import org.junit.Test; - -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscapeReverse; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait; -import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortraitReverse; - -public class OrientationTest extends BaseTest { - - @Test - public void testChangeDeviceOrientation() { - onView(isRoot()).perform(orientationLandscape()); - waitAction(2200); - onView(isRoot()).perform(orientationPortrait()); - waitAction(2500); - onView(isRoot()).perform(orientationLandscapeReverse()); - waitAction(500); - onView(isRoot()).perform(orientationPortraitReverse()); - waitAction(1250); - onView(isRoot()).perform(orientationLandscape()); - waitAction(750); - onView(isRoot()).perform(orientationPortrait()); - waitAction(950); - onView(isRoot()).perform(orientationLandscapeReverse()); - onView(isRoot()).perform(orientationPortraitReverse()); - onView(isRoot()).perform(orientationLandscape()); - onView(isRoot()).perform(orientationPortrait()); - } - - @Override - protected Class getActivityClass() { - return CameraAnimationTypeActivity.class; - } - -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt deleted file mode 100644 index cd139ccc40..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/TextureViewReopenTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.mapbox.mapboxsdk.maps - -import android.content.Intent -import android.support.test.InstrumentationRegistry -import android.support.test.filters.SdkSuppress -import android.support.test.runner.AndroidJUnit4 -import android.support.test.uiautomator.* -import org.hamcrest.CoreMatchers.notNullValue -import org.hamcrest.MatcherAssert.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import java.lang.Thread.sleep -import android.support.test.uiautomator.UiSelector -import android.support.test.uiautomator.UiScrollable - -private const val BASIC_SAMPLE_PACKAGE = "com.mapbox.mapboxsdk.testapp" -private const val LAUNCH_TIMEOUT = 5000L - -@RunWith(AndroidJUnit4::class) -@SdkSuppress(minSdkVersion = 18) -class TextureViewReopenTest { - - private lateinit var device: UiDevice - - @Before - fun startSimpleMapActivityFromHomeScreen() { - // Initialize UiDevice instance - device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) - - // Start from the home screen - device.pressHome() - - // Wait for launcher - val launcherPackage: String = device.launcherPackageName - assertThat(launcherPackage, notNullValue()) - device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT) - - // Launch the app - val context = InstrumentationRegistry.getInstrumentation().context - val intent = context.packageManager.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE).apply { - // Clear out any previous instances - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - } - context.startActivity(intent) - - // Wait for the app to appear - device.wait( - Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), - LAUNCH_TIMEOUT - ) - - // open TextureView debug activity - val appView = UiScrollable(UiSelector().scrollable(true)) - appView.scrollIntoView(UiSelector().text("TextureView debug")) - device.findObject(UiSelector().text("TextureView debug")).clickAndWaitForNewWindow() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - } - - @Test - fun reopenTextureViewDebugActivity() { - // return to home screen - device.pressHome() - - // press recent apps button - device.pressRecentApps() - - // click to reopen app - device.findObject(UiSelector().description("Mapbox Android SDK TestApp")).click() - - // wait for idle - device.waitForIdle(LAUNCH_TIMEOUT) - sleep(LAUNCH_TIMEOUT) - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt index 4866812e67..139695461d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt @@ -1,25 +1,27 @@ -package com.mapbox.mapboxsdk.testapp.maps +package com.mapbox.mapboxsdk.maps import android.graphics.PointF import android.support.test.espresso.UiController 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.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest -import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity + +import com.mapbox.mapboxsdk.testapp.activity.BaseTest +import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test -class VisibleRegionTest : EspressoTest() { +class VisibleRegionTest : BaseTest() { - private lateinit var mapView: MapView + override fun getActivityClass(): Class<*> { + return PixelTestActivity::class.java + } - override fun beforeTest() { + override + fun beforeTest() { super.beforeTest() - mapView = (rule.activity as EspressoTestActivity).mapView + mapView = (rule.activity as PixelTestActivity).mapView } @Test @@ -263,9 +265,9 @@ class VisibleRegionTest : EspressoTest() { @Test fun paddedTopVisibleRegionOverDatelineTest() { validateTestSetup() - invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap -> mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) - + ui.loopMainThreadForAtLeast(5000) val latLngs = listOf( mapboxMap.getLatLngFromScreenCoords(0f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), @@ -299,7 +301,7 @@ class VisibleRegionTest : EspressoTest() { mapboxMap.getLatLngFromScreenCoords(0f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f), mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), 0f) - .also { it.longitude += 360 }, + .also { it.longitude += 360 }, mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f) .also { it.longitude += 360 }, mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height.toFloat()) @@ -355,11 +357,11 @@ class VisibleRegionTest : EspressoTest() { mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 8.0)) val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; val latLngs = listOf( - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) ) @@ -371,29 +373,29 @@ class VisibleRegionTest : EspressoTest() { } } - @Test - fun visibleRotatedRegionOverDatelineTest() { - validateTestSetup() - invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) - val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; - val latLngs = listOf( - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f) - .also { it.longitude += 360 }, - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), - mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) - ) - - - for (bearing in 45 until 360 step 45) { - mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())); - val visibleRegion = mapboxMap.projection.visibleRegion - assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) }) - } - } + @Test + fun visibleRotatedRegionOverDatelineTest() { + validateTestSetup() + invoke(mapboxMap) { _: UiController, mapboxMap: MapboxMap -> + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0)) + val d = Math.min(mapboxMap.width, mapboxMap.height) / 4; + val latLngs = listOf( + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f - d / 2f, mapView.height / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f + d / 2f, mapView.height / 2f) + .also { it.longitude += 360 }, + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f - d / 2f), + mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f + d / 2f) + ) + + + for (bearing in 45 until 360 step 45) { + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(bearing.toDouble())); + val visibleRegion = mapboxMap.projection.visibleRegion + assertTrue(latLngs.all { visibleRegion.latLngBounds.contains(it) }) + } } + } private fun MapboxMap.getLatLngFromScreenCoords(x: Float, y: Float): LatLng { return this.projection.fromScreenLocation(PointF(x, y)) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java new file mode 100644 index 0000000000..6f256b4e56 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/module/telemetry/PerformanceEventTest.java @@ -0,0 +1,188 @@ +package com.mapbox.mapboxsdk.module.telemetry; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mapbox.mapboxsdk.Mapbox; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@RunWith(AndroidJUnit4.class) +public class PerformanceEventTest { + + @Test + public void checksPerformanceEventWithMetaData() throws Exception { + PerformanceEvent event = obtainPerformanceEvent(); + assertNotNull(event); + + Parcel parcel = Parcel.obtain(); + + event.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel); + assertNotNull(newPerfEvent); + + compare(event, newPerfEvent, "attributes", "style_id"); + compare(event, newPerfEvent, "counters", "int_value"); + compare(event, newPerfEvent, "counters", "long_value"); + compare(event, newPerfEvent, "counters", "double_value"); + assertEquals(getMetadata(event), getMetadata(newPerfEvent)); + } + + @Test + public void checksPerformanceEventOnlyRequiredData() throws Exception { + Bundle bundle = new Bundle(); + bundle.putString("property ignored", "value will be ignored"); + PerformanceEvent event = new PerformanceEvent(UUID.randomUUID().toString(), bundle); + assertNotNull(event); + + Parcel parcel = Parcel.obtain(); + event.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + PerformanceEvent newPerfEvent = PerformanceEvent.CREATOR.createFromParcel(parcel); + assertNotNull(newPerfEvent); + + assertEquals(getAttributes(event).size(), 0); + assertEquals(getCounters(event).size(), 0); + assertEquals(getAttributes(newPerfEvent).size(), 0); + assertEquals(getCounters(newPerfEvent).size(), 0); + assertEquals(getMetadata(event), getMetadata(newPerfEvent)); + } + + + private PerformanceEvent obtainPerformanceEvent() { + String styleStr = "mapbox://styles/mapbox/streets-v11"; + boolean testPerfEvent = true; + Double doubleValue = 40.5; + Long longValue = 40L; + Integer intValue = 40; + + List<Attribute<String>> attributes = new ArrayList<>(); + attributes.add( + new Attribute<>("style_id", styleStr)); + attributes.add( + new Attribute<>("test_perf_event", String.valueOf(testPerfEvent))); + + List<Attribute<? extends Number>> counters = new ArrayList(); + counters.add(new Attribute<>("long_value", longValue)); + counters.add(new Attribute<>("double_value", doubleValue)); + counters.add(new Attribute<>("int_value", intValue)); + + Gson gson = new Gson(); + + Bundle bundle = new Bundle(); + bundle.putString("attributes", gson.toJson(attributes)); + bundle.putString("counters", gson.toJson(counters)); + + JsonObject metaData = new JsonObject(); + metaData.addProperty("os", "android"); + metaData.addProperty("manufacturer", Build.MANUFACTURER); + metaData.addProperty("brand", Build.BRAND); + metaData.addProperty("device", Build.MODEL); + metaData.addProperty("version", Build.VERSION.RELEASE); + metaData.addProperty("abi", Build.CPU_ABI); + metaData.addProperty("country", Locale.getDefault().getISO3Country()); + metaData.addProperty("ram", getRam()); + metaData.addProperty("screenSize", getWindowSize()); + bundle.putString("metadata", metaData.toString()); + + return new PerformanceEvent(UUID.randomUUID().toString(), bundle); + } + + private void compare(PerformanceEvent event1, PerformanceEvent event2, String listFieldName, String name) + throws NoSuchFieldException, IllegalAccessException { + Object value1 = getValue(event1, listFieldName, name); + Object value2 = getValue(event2, listFieldName, name); + + if (value1 instanceof Double && value2 instanceof Double) { + assertEquals((Double)value1, (Double)value2, 0.00006); + } else { + assertEquals(value1, value2); + } + } + + private Object getPrivateFieldValue(Object object, String fieldName) + throws NoSuchFieldException, IllegalAccessException { + Field field = object.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(object); + } + + private Object getValue(PerformanceEvent event, String listFieldName, String name) + throws NoSuchFieldException, IllegalAccessException { + ArrayList list = (ArrayList)getPrivateFieldValue(event, listFieldName); + for (Object element : list) { + Object elementName = getPrivateFieldValue(element, "name"); + if (elementName != null && elementName.equals((String)name)) { + return getPrivateFieldValue(element, "value"); + } + } + return null; + } + + private JsonObject getMetadata(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (JsonObject)getPrivateFieldValue(event, "metadata"); + } + + private ArrayList getAttributes(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (ArrayList)getPrivateFieldValue(event, "attributes"); + } + + private ArrayList getCounters(PerformanceEvent event) + throws NoSuchFieldException, IllegalAccessException { + return (ArrayList)getPrivateFieldValue(event, "counters"); + } + + private static String getRam() { + ActivityManager actManager = + (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + actManager.getMemoryInfo(memInfo); + return String.valueOf(memInfo.totalMem); + } + + private static String getWindowSize() { + WindowManager windowManager = + (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + int width = metrics.widthPixels; + int height = metrics.heightPixels; + + return "{" + width + "," + height + "}"; + } + + private class Attribute<T> { + private String name; + private T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java index 7f73d6a7f3..1bf5a87970 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationChangeAction.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/OrientationAction.java @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.action; - import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; @@ -11,30 +10,31 @@ import android.view.View; import android.view.ViewGroup; import org.hamcrest.Matcher; +import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; -public class OrientationChangeAction implements ViewAction { +public class OrientationAction implements ViewAction { private final int orientation; - private OrientationChangeAction(int orientation) { + private OrientationAction(int orientation) { this.orientation = orientation; } public static ViewAction orientationLandscape() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } public static ViewAction orientationPortrait() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } public static ViewAction orientationLandscapeReverse() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); } public static ViewAction orientationPortraitReverse() { - return new OrientationChangeAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + return new OrientationAction(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); } @Override @@ -61,6 +61,10 @@ public class OrientationChangeAction implements ViewAction { activity.setRequestedOrientation(orientation); } + public static void invoke(ViewAction action) { + onView(isRoot()).perform(action); + } + private Activity getActivity(Context context) { while (context instanceof ContextWrapper) { if (context instanceof Activity) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java index 5d98ccb7f8..e3741f3d42 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java @@ -3,10 +3,11 @@ package com.mapbox.mapboxsdk.testapp.action; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.view.View; - import org.hamcrest.Matcher; +import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; public final class WaitAction implements ViewAction { @@ -30,5 +31,9 @@ public final class WaitAction implements ViewAction { public void perform(UiController uiController, View view) { uiController.loopMainThreadForAtLeast(loopTime); } + + public static void invoke(long loopTime) { + onView(isRoot()).perform(new WaitAction(loopTime)); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java index ea69f8adae..c91afe9b60 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseTest.java @@ -1,116 +1,96 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.app.Activity; -import android.support.test.espresso.Espresso; -import android.support.test.espresso.IdlingRegistry; -import android.support.test.espresso.IdlingResource; -import android.support.test.espresso.IdlingResourceTimeoutException; -import android.support.test.espresso.ViewInteraction; +import android.support.annotation.CallSuper; +import android.support.annotation.UiThread; import android.support.test.rule.ActivityTestRule; - import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; -import com.mapbox.mapboxsdk.testapp.action.WaitAction; -import com.mapbox.mapboxsdk.testapp.utils.FinishLoadingStyleIdlingResource; - -import com.mapbox.mapboxsdk.testapp.utils.MapboxIdlingResource; -import junit.framework.Assert; - import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.rules.TestName; - import timber.log.Timber; -import static android.support.test.espresso.Espresso.onView; -import static android.support.test.espresso.assertion.ViewAssertions.matches; -import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; /** * Base class for all Activity test hooking into an existing Activity that will load style. */ public abstract class BaseTest { + private static final int WAIT_TIMEOUT = 30; //seconds + @Rule - public ActivityTestRule<Activity> rule = new ActivityTestRule<>(getActivityClass()); + public ActivityTestRule rule = new ActivityTestRule<>(getActivityClass()); @Rule - public TestName testNameRule = new TestName(); + public TestName testName = new TestName(); protected MapboxMap mapboxMap; - protected MapboxIdlingResource idlingResource; + protected MapView mapView; + private final CountDownLatch latch = new CountDownLatch(1); @Before + @CallSuper public void beforeTest() { - try { - Timber.e(String.format( - "%s - %s - %s", - getClass().getSimpleName(), - testNameRule.getMethodName(), - "@Before test: register idle resource" - )); - idlingResource = (MapboxIdlingResource) generateIdlingResource(); - IdlingRegistry.getInstance().register(idlingResource); - Espresso.onIdle(); - mapboxMap = idlingResource.getMapboxMap(); - } catch (IdlingResourceTimeoutException idlingResourceTimeoutException) { - throw new RuntimeException( - String.format( - "Could not start %s test for %s.", - testNameRule.getMethodName(), - getActivityClass().getSimpleName() - ) - ); - } + initialiseMap(); + holdTestRunnerForStyleLoad(); } - protected IdlingResource generateIdlingResource() { - return new FinishLoadingStyleIdlingResource(rule.getActivity()); + @After + @CallSuper + public void afterTest() { + // override to add logic + } + + @UiThread + @CallSuper + protected void initMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + mapboxMap.getStyle(style -> latch.countDown()); } protected void validateTestSetup() { if (!Mapbox.isConnected()) { Timber.e("Not connected to the internet while running test"); } - - checkViewIsDisplayed(R.id.mapView); - Assert.assertNotNull(mapboxMap); - } - - protected MapboxMap getMapboxMap() { - return mapboxMap; + assertNotNull("MapView isn't initialised", mapView); + assertNotNull("MapboxMap isn't initialised", mapboxMap); + assertNotNull("Style isn't initialised", mapboxMap.getStyle()); + assertTrue("Style isn't fully loaded", mapboxMap.getStyle().isFullyLoaded()); } protected abstract Class getActivityClass(); - protected void checkViewIsDisplayed(int id) { - onView(withId(id)).check(matches(isDisplayed())); - } - - protected void waitAction() { - waitAction(500); - } - - protected void waitAction(long waitTime) { - onView(withId(R.id.mapView)).perform(new WaitAction(waitTime)); - } - - protected ViewInteraction onMapView() { - return onView(withId(R.id.mapView)); + private void initialiseMap() { + try { + rule.runOnUiThread(() -> { + mapView = rule.getActivity().findViewById(R.id.mapView); + mapView.getMapAsync(this::initMap); + }); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } } - protected MapboxMapAction getMapboxMapAction(MapboxMapAction.OnInvokeActionListener onInvokeActionListener) { - return new MapboxMapAction(onInvokeActionListener, mapboxMap); - } + private void holdTestRunnerForStyleLoad() { + boolean interrupted; + try { + interrupted = latch.await(WAIT_TIMEOUT, TimeUnit.SECONDS); + } catch (InterruptedException ignore) { + interrupted = true; + } - @After - public void afterTest() { - Timber.e(String.format("%s - %s", testNameRule.getMethodName(), "@After test: unregister idle resource")); - IdlingRegistry.getInstance().unregister(idlingResource); + if (!interrupted) { + Timber.e("Timeout occurred for %s", testName.getMethodName()); + validateTestSetup(); + } } -} +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java index dfb4a46180..97a73ba1cb 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/EspressoTest.java @@ -1,24 +1,28 @@ package com.mapbox.mapboxsdk.testapp.activity; -import android.support.test.espresso.IdlingResource; +import android.support.annotation.UiThread; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; -import com.mapbox.mapboxsdk.testapp.utils.LoadStyleIdlingResource; + /** * Base class for all tests using EspressoTestActivity as wrapper. * <p> - * Uses {@link LoadStyleIdlingResource} to load "assets/streets.json" as style. + * Loads "assets/streets.json" as style. * </p> */ public class EspressoTest extends BaseTest { @Override - protected IdlingResource generateIdlingResource() { - return new LoadStyleIdlingResource(rule.getActivity()); + protected final Class getActivityClass() { + return EspressoTestActivity.class; } + @UiThread @Override - protected final Class getActivityClass() { - return EspressoTestActivity.class; + protected void initMap(MapboxMap mapboxMap) { + mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json")); + super.initMap(mapboxMap); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java index 9fb823a377..559213af3d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/annotations/IconTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.testapp.annotations; import android.app.Activity; +import android.support.test.annotation.UiThreadTest; import android.support.v4.content.res.ResourcesCompat; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; @@ -31,117 +32,107 @@ public class IconTest extends EspressoTest { @Before public void beforeTest() { super.beforeTest(); - iconMap = new IconManagerResolver(getMapboxMap()).getIconMap(); - } - - @Test - public void testEmpty() { - assertTrue(iconMap.isEmpty()); + iconMap = new IconManagerResolver(mapboxMap).getIconMap(); } @Test + @UiThreadTest public void testAddSameIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker(); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(1, iconMap.size()); - assertEquals(2, iconMap.get(defaultMarker), 0); - })); + Icon defaultMarker = IconFactory.getInstance(rule.getActivity()).defaultMarker(); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(1, iconMap.size()); + assertEquals(2, iconMap.get(defaultMarker), 0); } @Test + @UiThreadTest public void testAddDifferentIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); - getMapboxMap().addMarker(new MarkerOptions().icon(icon).position(new LatLng())); - getMapboxMap().addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 2); - assertTrue(iconMap.containsKey(icon)); - assertTrue(iconMap.get(icon) == 1); - })); + Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); + mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 2); + assertTrue(iconMap.containsKey(icon)); + assertTrue(iconMap.get(icon) == 1); } @Test + @UiThreadTest public void testAddRemoveIconMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); - Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 2); - assertTrue(iconMap.containsKey(icon)); - assertTrue(iconMap.get(icon) == 1); - - mapboxMap.removeMarker(marker); - assertEquals(iconMap.size(), 1); - assertFalse(iconMap.containsKey(icon)); - })); + Icon icon = IconFactory.getInstance(rule.getActivity()).fromResource(R.drawable.mapbox_logo_icon); + Marker marker = mapboxMap.addMarker(new MarkerOptions().icon(icon).position(new LatLng())); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 2); + assertTrue(iconMap.containsKey(icon)); + assertTrue(iconMap.get(icon) == 1); + + mapboxMap.removeMarker(marker); + assertEquals(iconMap.size(), 1); + assertFalse(iconMap.containsKey(icon)); } @Test + @UiThreadTest public void testAddRemoveDefaultMarker() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - assertEquals(iconMap.size(), 1); + Marker marker = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + assertEquals(iconMap.size(), 1); - mapboxMap.removeMarker(marker); - assertEquals(iconMap.size(), 0); + mapboxMap.removeMarker(marker); + assertEquals(iconMap.size(), 0); - mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); - assertEquals(iconMap.size(), 1); - })); + mapboxMap.addMarker(new MarkerOptions().position(new LatLng())); + assertEquals(iconMap.size(), 1); } @Test + @UiThreadTest public void testAddRemoveMany() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - Activity activity = rule.getActivity(); - IconFactory iconFactory = IconFactory.getInstance(activity); - - // add 2 default icon markers - Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); - Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1))); - - // add 4 unique icon markers - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon)) - .position(new LatLng(3, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon)) - .position(new LatLng(4, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars, - ResourcesCompat.getColor(activity.getResources(), - R.color.blueAccent, activity.getTheme()))) - .position(new LatLng(5, 1)) - ); - mapboxMap.addMarker(new MarkerOptions() - .icon(iconFactory.fromResource(R.drawable.ic_android)) - .position(new LatLng(6, 1)) - ); - - assertEquals("Amount of icons should match 5", 5, iconMap.size()); - assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0); - - mapboxMap.removeMarker(defaultMarkerOne); - - assertEquals("Amount of icons should match 5", 5, iconMap.size()); - assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0); - - mapboxMap.removeMarker(defaultMarkerTwo); - - assertEquals("Amount of icons should match 4", 4, iconMap.size()); - assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker())); - - mapboxMap.clear(); - assertEquals("Amount of icons should match 0", 0, iconMap.size()); - })); + Activity activity = rule.getActivity(); + IconFactory iconFactory = IconFactory.getInstance(activity); + + // add 2 default icon markers + Marker defaultMarkerOne = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(1, 1))); + Marker defaultMarkerTwo = mapboxMap.addMarker(new MarkerOptions().position(new LatLng(2, 1))); + + // add 4 unique icon markers + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.mapbox_logo_icon)) + .position(new LatLng(3, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.mapbox_compass_icon)) + .position(new LatLng(4, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(IconUtils.drawableToIcon(activity, R.drawable.ic_stars, + ResourcesCompat.getColor(activity.getResources(), + R.color.blueAccent, activity.getTheme()))) + .position(new LatLng(5, 1)) + ); + mapboxMap.addMarker(new MarkerOptions() + .icon(iconFactory.fromResource(R.drawable.ic_android)) + .position(new LatLng(6, 1)) + ); + + assertEquals("Amount of icons should match 5", 5, iconMap.size()); + assertEquals("Refcounter of default marker should match 2", 2, iconMap.get(iconFactory.defaultMarker()), 0); + + mapboxMap.removeMarker(defaultMarkerOne); + + assertEquals("Amount of icons should match 5", 5, iconMap.size()); + assertEquals("Refcounter of default marker should match 1", 1, iconMap.get(iconFactory.defaultMarker()), 0); + + mapboxMap.removeMarker(defaultMarkerTwo); + + assertEquals("Amount of icons should match 4", 4, iconMap.size()); + assertNull("DefaultMarker shouldn't exist anymore", iconMap.get(iconFactory.defaultMarker())); + + mapboxMap.clear(); + assertEquals("Amount of icons should match 0", 0, iconMap.size()); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java index eb38bddf84..4365ea95ff 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraForTest.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.testapp.camera; import android.support.annotation.NonNull; +import android.support.test.annotation.UiThreadTest; import com.mapbox.geojson.Point; import com.mapbox.geojson.Polygon; import com.mapbox.mapboxsdk.camera.CameraPosition; @@ -18,123 +19,117 @@ import static org.junit.Assert.assertEquals; public class CameraForTest extends BaseTest { @Test + @UiThreadTest public void testGetCameraForLatLngBounds() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10)); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Bearing should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10)); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Bearing should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsPadding() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsBearing() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsTilt() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), 0, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), 0, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.264576975267, 0)).zoom(4.13).tilt(45).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForLatLngBoundsAll() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( - LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + CameraPosition actualPosition = mapboxMap.getCameraForLatLngBounds( + LatLngBounds.from(10, 10, -10, -10), new int[] {5, 5, 5, 5}, 45, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.3732134634, -0.3713191053)).zoom(3.63).tilt(45).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometry() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition)); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Bearing should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition)); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.16).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Bearing should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", expectedPosition.tilt, actualPosition.tilt, 0.01f); } @NonNull @@ -154,113 +149,108 @@ public class CameraForTest extends BaseTest { } @Test + @UiThreadTest public void testGetCameraForGeometryPadding() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(4.13).tilt(0).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryBearing() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.66).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryTilt() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), 0, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.2645769752, 0)).zoom(4.13).tilt(45).bearing(0).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryAll() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}, 45, 45); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry(Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}, 45, 45); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng(-0.373213463, -0.37131910534)).zoom(3.63).tilt(45).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Test + @UiThreadTest public void testGetCameraForGeometryDeprecatedApi() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - List<List<Point>> polygonDefinition = getPolygonDefinition(); - CameraPosition actualPosition = mapboxMap.getCameraForGeometry( - Polygon.fromLngLats(polygonDefinition), - new int[] {5, 5, 5, 5}, - 45, 0); - CameraPosition expectedPosition = new CameraPosition.Builder() - .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build(); - assertEquals("Latitude should match", - expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); - assertEquals("Longitude should match", - expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); - assertEquals("Zoom should match", - expectedPosition.zoom, actualPosition.zoom, 0.01f); - assertEquals("Tilt should match", - expectedPosition.tilt, actualPosition.tilt, 0.01f); - assertEquals("Bearing should match", - expectedPosition.bearing, actualPosition.bearing, 0.01f); - })); + List<List<Point>> polygonDefinition = getPolygonDefinition(); + CameraPosition actualPosition = mapboxMap.getCameraForGeometry( + Polygon.fromLngLats(polygonDefinition), + new int[] {5, 5, 5, 5}, + 45, 0); + CameraPosition expectedPosition = new CameraPosition.Builder() + .target(new LatLng()).zoom(3.63).tilt(0).bearing(45).build(); + assertEquals("Latitude should match", + expectedPosition.target.getLatitude(), actualPosition.target.getLatitude(), 0.00001f); + assertEquals("Longitude should match", + expectedPosition.target.getLongitude(), actualPosition.target.getLongitude(), 0.00001f); + assertEquals("Zoom should match", + expectedPosition.zoom, actualPosition.zoom, 0.01f); + assertEquals("Tilt should match", + expectedPosition.tilt, actualPosition.tilt, 0.01f); + assertEquals("Bearing should match", + expectedPosition.bearing, actualPosition.bearing, 0.01f); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt index 418191e91a..2731b20db7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/fragment/MapDialogFragmentTest.kt @@ -10,6 +10,7 @@ import android.support.test.runner.AndroidJUnit4 import com.mapbox.mapboxsdk.testapp.R import com.mapbox.mapboxsdk.testapp.action.WaitAction import com.mapbox.mapboxsdk.testapp.activity.maplayout.MapInDialogActivity +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -25,9 +26,10 @@ class MapDialogFragmentTest { var activityRule: ActivityTestRule<MapInDialogActivity> = ActivityTestRule(MapInDialogActivity::class.java) @Test + @Ignore fun openCloseDialog() { onView(withId(R.id.button_open_dialog)).perform(click()) - onView(withId(R.id.mapView)).perform(WaitAction(2500)) + Thread.sleep(2500) Espresso.pressBack() } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java index c34e76a6e5..f30b3aa8cf 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/GeoJsonConversionTest.java @@ -1,5 +1,6 @@ package com.mapbox.mapboxsdk.testapp.geometry; +import android.support.test.annotation.UiThreadTest; import com.google.gson.JsonArray; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; @@ -13,11 +14,13 @@ import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.style.sources.GeometryTileProvider; +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestingAsyncUtils; - import org.junit.Test; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static com.mapbox.geojson.Feature.fromGeometry; import static com.mapbox.geojson.FeatureCollection.fromFeatures; import static com.mapbox.geojson.GeometryCollection.fromGeometries; @@ -35,101 +38,94 @@ public class GeoJsonConversionTest extends EspressoTest { // Regression test for #12343 @Test + @UiThreadTest public void testEmptyFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromGeometries(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testPointFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(Point.fromLngLat(0.0, 0.0))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiPointFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } - @Test + @UiThreadTest public void testPolygonFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(Polygon.fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiPolygonFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList())))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromPolygon(Polygon.fromLngLats(emptyList())))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testLineStringFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLngLats(emptyList()))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } @Test + @UiThreadTest public void testMultiLineStringFeatureCollection() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { - mapboxMap.getStyle().addSource( - new CustomGeometrySource("test-id", - new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList())))))) - ) - ); - mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); - })); + mapboxMap.getStyle().addSource( + new CustomGeometrySource("test-id", + new CustomProvider(fromFeatures(singletonList(fromGeometry(fromLineString(fromLngLats(emptyList())))))) + ) + ); + mapboxMap.getStyle().addLayer(new SymbolLayer("test-id", "test-id")); } + @Test public void testNegativeNumberPropertyConversion() { validateTestSetup(); - onMapView().perform(getMapboxMapAction((uiController, mapboxMap) -> { + onView(isRoot()).perform(new MapboxMapAction((uiController, mapboxMap) -> { LatLng latLng = new LatLng(); Feature feature = Feature.fromGeometry(Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude())); @@ -148,10 +144,10 @@ public class GeoJsonConversionTest extends EspressoTest { ); mapboxMap.getStyle().addLayer(layer); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng)).isEmpty()); - })); + }, mapboxMap)); } class CustomProvider implements GeometryTileProvider { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt index 84af279bd0..ac73b028f3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/StyleLoadTest.kt @@ -18,14 +18,6 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class StyleLoadTest : EspressoTest() { - private lateinit var mapView: MapView - - @Before - override fun beforeTest() { - super.beforeTest() - mapView = (rule.activity as EspressoTestActivity).mapView - } - @Test fun updateSourceAfterStyleLoad() { validateTestSetup() diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java index 0fadd33325..ca5c9adc1f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/AttributionTest.java @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.testapp.maps.widgets; import android.app.Instrumentation; import android.content.Intent; import android.net.Uri; +import android.os.Build; import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.espresso.intent.Intents; @@ -31,12 +32,14 @@ import static android.support.test.espresso.intent.Intents.intended; import static android.support.test.espresso.intent.Intents.intending; import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction; import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData; +import static android.support.test.espresso.matcher.RootMatchers.isDialog; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.anything; import static org.hamcrest.core.IsNot.not; +import static org.junit.Assume.assumeTrue; public class AttributionTest extends EspressoTest { @@ -126,15 +129,20 @@ public class AttributionTest extends EspressoTest { @Test public void testTelemetryDialog() { + assumeTrue( + "Can only run on API Level 23 or newer because of instability", + Build.VERSION.SDK_INT >= 23 + ); + validateTestSetup(); // click on View to open dialog onView(withId(R.id.attributionView)).perform(click()); - onView(withText(R.string.mapbox_attributionsDialogTitle)).check(matches(isDisplayed())); + onView(withText(R.string.mapbox_attributionsDialogTitle)).inRoot(isDialog()).check(matches(isDisplayed())); // click on item to open second dialog - onView(withText(R.string.mapbox_telemetrySettings)).perform(click()); - onView(withText(R.string.mapbox_attributionTelemetryTitle)).check(matches(isDisplayed())); + onView(withText(R.string.mapbox_telemetrySettings)).inRoot(isDialog()).perform(click()); + onView(withText(R.string.mapbox_attributionTelemetryTitle)).inRoot(isDialog()).check(matches(isDisplayed())); } @After @@ -206,4 +214,4 @@ public class AttributionTest extends EspressoTest { interface InvokeViewAction { void onViewAction(UiController uiController, View view); } -} +}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java index 1cdf1423a3..8b62ee7612 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java @@ -4,6 +4,7 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.action.WaitAction; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; import com.mapbox.mapboxsdk.testapp.utils.TestConstants; import org.junit.Ignore; @@ -55,7 +56,7 @@ public class CompassViewTest extends EspressoTest { .build() ))); onView(withId(R.id.compassView)).perform(click()); - waitAction(); + WaitAction.invoke(500); onView(withId(R.id.compassView)).check(matches(not(isDisplayed()))); invoke(mapboxMap, (uiController, mapboxMap) -> { CameraPosition cameraPosition = mapboxMap.getCameraPosition(); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt index 144d67feee..8e5f3f7c5f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/offline/OfflineManagerTest.kt @@ -1,59 +1,43 @@ package com.mapbox.mapboxsdk.testapp.offline import android.content.Context -import android.support.test.espresso.Espresso -import android.support.test.espresso.IdlingRegistry -import android.support.test.espresso.UiController -import android.support.test.espresso.idling.CountingIdlingResource +import android.support.test.rule.ActivityTestRule import android.support.test.runner.AndroidJUnit4 -import com.mapbox.mapboxsdk.maps.MapboxMap import com.mapbox.mapboxsdk.offline.OfflineManager import com.mapbox.mapboxsdk.offline.OfflineRegion import com.mapbox.mapboxsdk.storage.FileSource -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest +import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity import com.mapbox.mapboxsdk.testapp.utils.FileUtils +import org.junit.FixMethodOrder +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.junit.runners.MethodSorters import java.io.IOException +import java.util.concurrent.CountDownLatch +@FixMethodOrder(MethodSorters.NAME_ASCENDING) @RunWith(AndroidJUnit4::class) -class OfflineManagerTest : EspressoTest() { +class OfflineManagerTest { companion object { private const val TEST_DB_FILE_NAME = "offline_test.db" + private lateinit var mergedRegion: OfflineRegion } - private val context: Context by lazy { rule.activity } - - private lateinit var offlineIdlingResource: CountingIdlingResource - - override fun beforeTest() { - super.beforeTest() - offlineIdlingResource = CountingIdlingResource("idling_resource") - IdlingRegistry.getInstance().register(offlineIdlingResource) - } + @Rule + @JvmField + var rule = ActivityTestRule(FeatureOverviewActivity::class.java) - @Test - fun offlineMergeListDeleteTest() { - validateTestSetup() + private val context: Context by lazy { rule.activity } - invoke(mapboxMap) { _: UiController, _: MapboxMap -> - offlineIdlingResource.increment() + @Test(timeout = 30_000) + fun a_copyFileFromAssets() { + val latch = CountDownLatch(1) + rule.runOnUiThread { FileUtils.CopyFileFromAssetsTask(rule.activity, object : FileUtils.OnFileCopiedFromAssetsListener { override fun onFileCopiedFromAssets() { - OfflineManager.getInstance(context).mergeOfflineRegions( - FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME, - object : OfflineManager.MergeOfflineRegionsCallback { - override fun onMerge(offlineRegions: Array<out OfflineRegion>?) { - assert(offlineRegions?.size == 1) - offlineIdlingResource.decrement() - } - - override fun onError(error: String?) { - throw RuntimeException("Unable to merge external offline database. $error") - } - }) + latch.countDown() } override fun onError() { @@ -61,43 +45,62 @@ class OfflineManagerTest : EspressoTest() { } }).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(rule.activity)) } + latch.await() + } + + @Test(timeout = 30_000) + fun b_mergeRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { + OfflineManager.getInstance(context).mergeOfflineRegions( + FileSource.getResourcesCachePath(rule.activity) + "/" + TEST_DB_FILE_NAME, + object : OfflineManager.MergeOfflineRegionsCallback { + override fun onMerge(offlineRegions: Array<out OfflineRegion>?) { + assert(offlineRegions?.size == 1) + latch.countDown() + } + + override fun onError(error: String?) { + throw RuntimeException("Unable to merge external offline database. $error") + } + }) + } + latch.await() + } - invoke(mapboxMap) { _: UiController, _: MapboxMap -> - offlineIdlingResource.increment() + @Test(timeout = 30_000) + fun c_listRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { OfflineManager.getInstance(context).listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback { override fun onList(offlineRegions: Array<out OfflineRegion>?) { assert(offlineRegions?.size == 1) - if (offlineRegions != null) { - for (region in offlineRegions) { - offlineIdlingResource.increment() - region.delete(object : OfflineRegion.OfflineRegionDeleteCallback { - override fun onDelete() { - offlineIdlingResource.decrement() - } - - override fun onError(error: String?) { - throw RuntimeException("Unable to delete region with ID: ${region.id}. $error") - } - }) - } - } else { - throw RuntimeException("Unable to find merged region.") - } - offlineIdlingResource.decrement() + mergedRegion = offlineRegions!![0] + latch.countDown() } override fun onError(error: String?) { - throw RuntimeException("Unable to obtain offline regions list. $error") + throw RuntimeException("Unable to merge external offline database. $error") } }) } - - // waiting for offline idling resource - Espresso.onIdle() + latch.await() } - override fun afterTest() { - super.afterTest() - IdlingRegistry.getInstance().unregister(offlineIdlingResource) + @Test(timeout = 30_000) + fun d_deleteRegion() { + val latch = CountDownLatch(1) + rule.runOnUiThread { + mergedRegion.delete(object : OfflineRegion.OfflineRegionDeleteCallback { + override fun onDelete() { + latch.countDown() + } + + override fun onError(error: String?) { + throw RuntimeException("Unable to delete region") + } + }) + } + latch.await() } }
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index eb458ab8f5..a6238ebf14 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -6,8 +6,9 @@ import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_POOL_LIMIT import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_PREFIX import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke -import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape -import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait +import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationLandscape +import com.mapbox.mapboxsdk.testapp.action.OrientationAction.orientationPortrait +import com.mapbox.mapboxsdk.testapp.action.WaitAction import com.mapbox.mapboxsdk.testapp.activity.BaseTest import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LAYER @@ -25,11 +26,11 @@ class CustomGeometrySourceTest : BaseTest() { @Ignore fun sourceNotLeakingThreadsTest() { validateTestSetup() - waitAction(4000) + WaitAction.invoke(4000) onView(isRoot()).perform(orientationLandscape()) - waitAction(2000) + WaitAction.invoke(2000) onView(isRoot()).perform(orientationPortrait()) - waitAction(2000) + WaitAction.invoke(2000) Assert.assertFalse("Threads should be shutdown when the source is destroyed.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(THREAD_PREFIX) @@ -42,9 +43,9 @@ class CustomGeometrySourceTest : BaseTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> mapboxMap.style!!.removeLayer(ID_GRID_LAYER) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.removeSource(ID_GRID_SOURCE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) Assert.assertTrue("There should be no threads running when the source is removed.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) @@ -58,12 +59,12 @@ class CustomGeometrySourceTest : BaseTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> mapboxMap.style!!.removeLayer((rule.activity as GridSourceActivity).layer) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.removeSource(ID_GRID_SOURCE) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) mapboxMap.style!!.addSource((rule.activity as GridSourceActivity).source) mapboxMap.style!!.addLayer((rule.activity as GridSourceActivity).layer) - TestingAsyncUtils.waitForLayer(uiController, idlingResource.mapView) + TestingAsyncUtils.waitForLayer(uiController, mapView) Assert.assertTrue("Threads should be restarted when the source is re-added to the map.", Thread.getAllStackTraces().keys.filter { it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java index 75dcbf1209..ff3b2a9d6d 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java @@ -252,7 +252,7 @@ public class ExpressionTest extends EspressoTest { ) )); mapboxMap.getStyle().addLayer(layer); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -262,7 +262,7 @@ public class ExpressionTest extends EspressoTest { literal(ColorUtils.colorToRgbaString(Color.RED)) ) )); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -272,7 +272,7 @@ public class ExpressionTest extends EspressoTest { literal(ColorUtils.colorToRgbaString(Color.RED)) ) )); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); }); @@ -292,7 +292,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("test") ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -315,7 +315,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("test", formatFontScale(1.75)) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -341,7 +341,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -371,7 +371,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -402,7 +402,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -436,7 +436,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("\ntest2", formatFontScale(2), formatTextColor(Color.BLUE)) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse( mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer").isEmpty() @@ -472,7 +472,7 @@ public class ExpressionTest extends EspressoTest { ) ); layer.setProperties(textField(expression)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -504,7 +504,7 @@ public class ExpressionTest extends EspressoTest { formatEntry("\ntest2", formatFontScale(2)) ); layer.setProperties(textField(expression), textColor("rgba(128, 0, 0, 1)")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -524,7 +524,7 @@ public class ExpressionTest extends EspressoTest { mapboxMap.getStyle().addLayer(layer); layer.setProperties(textField("test")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); @@ -550,7 +550,7 @@ public class ExpressionTest extends EspressoTest { new FormattedSection("test", null, null, "rgba(0, 255, 0, 1)") ); layer.setProperties(textField(formatted), textColor("rgba(128, 0, 0, 1)")); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") .isEmpty()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java index 92d060fee4..99e0ae4016 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java @@ -94,7 +94,7 @@ public class GeoJsonSourceTests extends EspressoTest { } source.setGeoJson(Point.fromLngLat(20, 55)); - TestingAsyncUtils.INSTANCE.waitForLayer(uiController, idlingResource.getMapView()); + TestingAsyncUtils.INSTANCE.waitForLayer(uiController, mapView); assertEquals(1, mapboxMap.queryRenderedFeatures( mapboxMap.getProjection().toScreenLocation( new LatLng(55, 20)), "layer").size()); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java deleted file mode 100644 index 0e4c8f3f2e..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.style; - -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.support.test.runner.AndroidJUnit4; - -import com.mapbox.mapboxsdk.testapp.R; -import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; - -import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * CRUD tests around Image - */ -@RunWith(AndroidJUnit4.class) -public class ImageTest extends EspressoTest { - - private static final String IMAGE_ID = "test.image"; - - @Test - public void testAddGetImage() { - validateTestSetup(); - MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { - Drawable drawable = rule.getActivity().getResources().getDrawable(R.drawable.ic_launcher_round); - assertTrue(drawable instanceof BitmapDrawable); - - Bitmap bitmapSet = ((BitmapDrawable) drawable).getBitmap(); - mapboxMap.getStyle().addImage(IMAGE_ID, bitmapSet); - - // adding an image requires converting the image with an asynctask - uiController.loopMainThreadForAtLeast(200); - - Bitmap bitmapGet = mapboxMap.getStyle().getImage(IMAGE_ID); - assertTrue(bitmapGet.sameAs(bitmapSet)); - - mapboxMap.getStyle().removeImage(IMAGE_ID); - assertNull(mapboxMap.getStyle().getImage(IMAGE_ID)); - }); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt new file mode 100644 index 0000000000..9cef677e7c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ImageTest.kt @@ -0,0 +1,75 @@ +package com.mapbox.mapboxsdk.testapp.style + +import android.graphics.Bitmap +import android.graphics.drawable.BitmapDrawable +import android.support.test.runner.AndroidJUnit4 +import com.mapbox.mapboxsdk.testapp.R +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction +import com.mapbox.mapboxsdk.testapp.activity.EspressoTest +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +/** + * CRUD tests around Image + */ +@RunWith(AndroidJUnit4::class) +class ImageTest : EspressoTest() { + + companion object { + private const val IMAGE_ID = "test.image" + } + + @Test + fun testAddGetImage() { + validateTestSetup() + MapboxMapAction.invoke(mapboxMap) { uiController, mapboxMap -> + val drawable = rule.activity.resources.getDrawable(R.drawable.ic_launcher_round) + assertTrue(drawable is BitmapDrawable) + + val bitmapSet = (drawable as BitmapDrawable).bitmap + mapboxMap.style!!.addImage(IMAGE_ID, bitmapSet) + + // adding an image requires converting the image with an asynctask + uiController.loopMainThreadForAtLeast(200) + + val bitmapGet = mapboxMap.style!!.getImage(IMAGE_ID) + assertTrue(bitmapGet!!.similarTo(bitmapSet)) + + mapboxMap.style!!.removeImage(IMAGE_ID) + assertNull(mapboxMap.style!!.getImage(IMAGE_ID)) + } + } +} + +/** + * Alternative implementation of Bitmap.sameAs #14060 + */ +fun Bitmap.similarTo(other: Bitmap): Boolean { + if (invalidConfig(other)) { + return false + } + + // Allocate arrays + val argb = IntArray(width * height) + val argbOther = IntArray(other.width * other.height) + getPixels(argb, 0, width, 0, 0, width, height) + other.getPixels(argbOther, 0, width, 0, 0, width, height) + + // Alpha channel special check + if (config == Bitmap.Config.ALPHA_8) { + // in this case we have to manually compare the alpha channel as the rest is garbage. + val length = width * height + for (i in 0 until length) { + if (argb[i] and -0x1000000 != argbOther[i] and -0x1000000) { + return false + } + } + return true + } + return Arrays.equals(argb, argbOther) +} + +fun Bitmap.invalidConfig(other: Bitmap): Boolean = this.config != other.config || this.width != other.width || this.height != other.height
\ No newline at end of file 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 ed39f36e32..a4a34e752e 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 @@ -2,12 +2,10 @@ 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; import android.support.test.runner.AndroidJUnit4; import android.view.View; - import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.FillLayer; @@ -22,20 +20,16 @@ import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.style.sources.VectorSource; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.activity.EspressoTest; - import junit.framework.Assert; - import org.hamcrest.Matcher; -import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; +import timber.log.Timber; import java.net.MalformedURLException; import java.net.URL; 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; @@ -366,11 +360,6 @@ public class RuntimeStyleTests extends EspressoTest { } } - @After - public void unregisterIntentServiceIdlingResource() { - Espresso.unregisterIdlingResources(idlingResource); - } - public abstract class BaseViewAction implements ViewAction { @Override 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 149064d684..ae2c6d98f6 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 @@ -559,7 +559,7 @@ public class SymbolLayerTest extends BaseLayerTest { assertNull(layer.getTextJustify().getValue()); // Set and Get - String propertyValue = TEXT_JUSTIFY_LEFT; + String propertyValue = TEXT_JUSTIFY_AUTO; layer.setProperties(textJustify(propertyValue)); assertEquals(layer.getTextJustify().getValue(), propertyValue); } @@ -579,6 +579,32 @@ public class SymbolLayerTest extends BaseLayerTest { @Test @UiThreadTest + public void testTextRadialOffsetAsConstant() { + Timber.i("text-radial-offset"); + assertNotNull(layer); + assertNull(layer.getTextRadialOffset().getValue()); + + // Set and Get + Float propertyValue = 0.3f; + layer.setProperties(textRadialOffset(propertyValue)); + assertEquals(layer.getTextRadialOffset().getValue(), propertyValue); + } + + @Test + @UiThreadTest + public void testTextVariableAnchorAsConstant() { + Timber.i("text-variable-anchor"); + assertNotNull(layer); + assertNull(layer.getTextVariableAnchor().getValue()); + + // Set and Get + String[] propertyValue = new String[0]; + layer.setProperties(textVariableAnchor(propertyValue)); + assertEquals(layer.getTextVariableAnchor().getValue(), propertyValue); + } + + @Test + @UiThreadTest public void testTextAnchorAsConstant() { Timber.i("text-anchor"); assertNotNull(layer); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java deleted file mode 100644 index 323d2c0f15..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/FinishLoadingStyleIdlingResource.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.WorkerThread; -import com.mapbox.mapboxsdk.maps.MapboxMap; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class FinishLoadingStyleIdlingResource extends MapboxIdlingResource { - - @WorkerThread - public FinishLoadingStyleIdlingResource(final Activity activity) { - new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity)); - } - - @Override - public void initMap(MapboxMap mapboxMap) { - super.initMap(mapboxMap); - mapboxMap.getStyle(style -> { - assertNotNull(style); - assertTrue(style.isFullyLoaded()); - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - } - - @Override - public boolean isIdleNow() { - return getMapboxMap() != null && getMapboxMap().getStyle() != null; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java deleted file mode 100644 index 5dead21fbb..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/LoadStyleIdlingResource.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.UiThread; -import android.support.annotation.WorkerThread; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Style; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -public class LoadStyleIdlingResource extends MapboxIdlingResource { - - private Style style; - - @WorkerThread - public LoadStyleIdlingResource(final Activity activity) { - new Handler(Looper.getMainLooper()).post(() -> inflateMap(activity)); - } - - @UiThread - public void initMap(MapboxMap mapboxMap) { - super.initMap(mapboxMap); - mapboxMap.setStyle("asset://streets.json", style -> { - assertNotNull(style); - assertTrue(style.isFullyLoaded()); - this.style = style; - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - } - - @Override - public boolean isIdleNow() { - return style != null; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java deleted file mode 100644 index a05221d618..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/MapboxIdlingResource.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.support.annotation.UiThread; -import android.support.test.espresso.IdlingResource; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.testapp.R; - -public abstract class MapboxIdlingResource implements IdlingResource { - - private MapView mapView; - private MapboxMap mapboxMap; - IdlingResource.ResourceCallback resourceCallback; - - @UiThread - void inflateMap(Activity activity) { - mapView = activity.findViewById(R.id.mapView); - if (mapView != null) { - mapView.getMapAsync(this::initMap); - } - } - - @UiThread - protected void initMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } - - @Override - public String getName() { - return getClass().getSimpleName(); - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - public MapboxMap getMapboxMap() { - return mapboxMap; - } - - public MapView getMapView() { - return mapView; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java deleted file mode 100644 index 7696447289..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/OnMapReadyIdlingResource.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.utils; - -import android.app.Activity; -import android.os.Handler; -import android.os.Looper; -import android.support.annotation.WorkerThread; -import android.support.test.espresso.IdlingResource; - -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.testapp.R; - -public class OnMapReadyIdlingResource implements IdlingResource { - - private boolean styleLoaded; - private MapboxMap mapboxMap; - private IdlingResource.ResourceCallback resourceCallback; - - @WorkerThread - public OnMapReadyIdlingResource(final Activity activity) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(() -> { - MapView mapView = activity.findViewById(R.id.mapView); - if (mapView != null) { - mapView.addOnDidFinishLoadingStyleListener(() -> { - styleLoaded = true; - if (resourceCallback != null) { - resourceCallback.onTransitionToIdle(); - } - }); - mapView.getMapAsync(this::initMap); - } - }); - } - - private void initMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - mapboxMap.setStyle(new Style.Builder().fromUrl("asset://streets.json")); - } - - @Override - public String getName() { - return getClass().getSimpleName(); - } - - @Override - public boolean isIdleNow() { - return styleLoaded; - } - - @Override - public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { - this.resourceCallback = resourceCallback; - } - - public MapboxMap getMapboxMap() { - return mapboxMap; - } -}
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 2fa26f822a..017fe3ddca 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -173,10 +173,11 @@ <activity android:name=".activity.fragment.FragmentBackStackActivity" android:description="@string/description_map_fragment_backstack" - android:label="@string/activity_map_fragment_backstack"> + android:label="@string/activity_map_fragment_backstack" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> @@ -399,7 +400,7 @@ android:label="@string/activity_viewpager"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> @@ -407,7 +408,8 @@ <activity android:name=".activity.maplayout.SimpleMapActivity" android:description="@string/description_simple_map" - android:label="@string/activity_simple_map"> + android:label="@string/activity_simple_map" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" android:value="@string/category_basic" /> @@ -720,7 +722,8 @@ <activity android:name=".activity.textureview.TextureViewDebugModeActivity" android:description="@string/description_textureview_debug" - android:label="@string/activity_textureview_debug"> + android:label="@string/activity_textureview_debug" + android:launchMode="singleInstance"> <meta-data android:name="@string/category" android:value="@string/category_basic" /> @@ -895,27 +898,49 @@ android:value=".activity.FeatureOverviewActivity" /> </activity> <activity - android:name=".activity.maplayout.RecyclerViewActivity" - android:description="@string/description_recyclerview" - android:label="@string/activity_recyclerview"> + android:name=".activity.maplayout.TextureRecyclerViewActivity" + android:description="@string/description_recyclerview_textureview" + android:label="@string/activity_recyclerview_textureview"> <meta-data android:name="@string/category" - android:value="@string/category_maplayout" /> + android:value="@string/category_integration" /> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + </activity> + <activity + android:name=".activity.maplayout.GLSurfaceRecyclerViewActivity" + android:description="@string/description_recyclerview_glsurfaceview" + android:label="@string/activity_recyclerview_glsurfaceview"> + <meta-data + android:name="@string/category" + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> </activity> <activity android:name=".activity.fragment.NestedViewPagerActivity" - android:description="@string/description_recyclerview" + android:description="@string/description_nested_viewpager" android:label="@string/activity_nested_viewpager"> <meta-data android:name="@string/category" - android:value="@string/category_fragment" /> + android:value="@string/category_integration" /> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".activity.FeatureOverviewActivity" /> </activity> + <activity + android:name=".activity.telemetry.PerformanceMeasurementActivity" + android:description="@string/description_performance_measurement" + android:label="@string/activity_performance_measurement"> + <meta-data + android:name="@string/category" + android:value="@string/category_telemetry" /> + <meta-data + android:name="android.support.PARENT_ACTIVITY" + android:value=".activity.FeatureOverviewActivity" /> + </activity> <!-- For Instrumentation tests --> <activity android:name=".activity.style.RuntimeStyleTimingTestActivity" @@ -924,6 +949,9 @@ android:name=".activity.espresso.EspressoTestActivity" android:screenOrientation="portrait" /> <activity + android:name=".activity.espresso.PixelTestActivity" + android:screenOrientation="portrait" /> + <activity android:name=".activity.espresso.DeviceIndependentTestActivity" android:screenOrientation="portrait" /> <activity diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java index 9ade97f91e..d5cff301db 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 @@ -40,7 +40,7 @@ public class MapboxApplication extends Application { initializeMapbox(); } - private boolean initializeLeakCanary() { + protected boolean initializeLeakCanary() { if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java index f4639b0f1a..ed5364655e 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/GestureDetectorActivity.java @@ -267,7 +267,18 @@ public class GestureDetectorActivity extends AppCompatActivity { if (enabled) { focalPointLatLng = new LatLng(51.50325, -0.12968); marker = mapboxMap.addMarker(new MarkerOptions().position(focalPointLatLng)); - mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16)); + mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16), + new MapboxMap.CancelableCallback() { + @Override + public void onCancel() { + recalculateFocalPoint(); + } + + @Override + public void onFinish() { + recalculateFocalPoint(); + } + }); } else { if (marker != null) { mapboxMap.removeMarker(marker); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt new file mode 100644 index 0000000000..b69d1ee5ed --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/espresso/PixelTestActivity.kt @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.testapp.activity.espresso + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R + +/** + * Test activity used for instrumentation tests that require a specific device size. + */ +class PixelTestActivity : AppCompatActivity(), OnMapReadyCallback { + + lateinit var mapView: MapView + lateinit var mapboxMap: MapboxMap + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_pixel_test) + mapView = findViewById(R.id.mapView) + mapView.onCreate(savedInstanceState) + mapView.getMapAsync(this) + } + + override fun onMapReady(map: MapboxMap) { + mapboxMap = map + mapboxMap.setStyle(Style.MAPBOX_STREETS) + } + + public override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + public override fun onPause() { + super.onPause() + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onDestroy() { + super.onDestroy() + mapView.onDestroy() + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } +} 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 472b9b7d57..c7f530b123 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 @@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapFragment; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.testapp.R; /** @@ -24,6 +23,7 @@ import com.mapbox.mapboxsdk.testapp.R; public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener { + private static final String TAG = "com.mapbox.map"; private MapboxMap mapboxMap; private MapView mapView; private boolean initialCameraAnimation = true; @@ -32,14 +32,18 @@ public class MapFragmentActivity extends AppCompatActivity implements MapFragmen protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); + + MapFragment mapFragment; if (savedInstanceState == null) { - MapFragment mapFragment = MapFragment.newInstance(createFragmentOptions()); + mapFragment = MapFragment.newInstance(createFragmentOptions()); getFragmentManager() .beginTransaction() - .add(R.id.fragment_container, mapFragment, "com.mapbox.map") + .add(R.id.fragment_container, mapFragment, TAG) .commit(); - mapFragment.getMapAsync(this); + } else { + mapFragment = (MapFragment) getFragmentManager().findFragmentByTag(TAG); } + mapFragment.getMapAsync(this); } private MapboxMapOptions createFragmentOptions() { 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 4baf40d51b..7fd84bcd25 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 @@ -3,16 +3,15 @@ package com.mapbox.mapboxsdk.testapp.activity.fragment; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; - import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; -import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapFragment; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.maps.Style; import com.mapbox.mapboxsdk.maps.SupportMapFragment; import com.mapbox.mapboxsdk.testapp.R; @@ -25,6 +24,7 @@ import com.mapbox.mapboxsdk.testapp.R; public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback, OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener { + private static final String TAG = "com.mapbox.map"; private MapboxMap mapboxMap; private MapView mapView; private boolean initialCameraAnimation = true; @@ -33,14 +33,18 @@ public class SupportMapFragmentActivity extends AppCompatActivity implements Map protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_fragment); + SupportMapFragment mapFragment; if (savedInstanceState == null) { - SupportMapFragment mapFragment = SupportMapFragment.newInstance(createFragmentOptions()); + mapFragment = SupportMapFragment.newInstance(createFragmentOptions()); getSupportFragmentManager() .beginTransaction() - .add(R.id.fragment_container, mapFragment, "com.mapbox.map") + .add(R.id.fragment_container, mapFragment, TAG) .commit(); - mapFragment.getMapAsync(this); + } else { + mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag(TAG); } + mapFragment.getMapAsync(this); + } private MapboxMapOptions createFragmentOptions() { 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 deleted file mode 100644 index c494842b14..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.fragment; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentStatePagerAdapter; -import android.support.v4.view.ViewPager; -import android.support.v7.app.AppCompatActivity; - -import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.maps.MapboxMapOptions; -import com.mapbox.mapboxsdk.maps.Style; -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 { - - private ViewPager viewPager; - private MapFragmentAdapter adapter; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_viewpager); - - viewPager = (ViewPager) findViewById(R.id.viewpager); - if (viewPager != null) { - adapter = new MapFragmentAdapter(getSupportFragmentManager()); - viewPager.setAdapter(adapter); - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - - int currentPosition = viewPager.getCurrentItem(); - SupportMapFragment mapFragment; - - if (Math.abs(0 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 0); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.MAPBOX_STREETS); - }); - } - - if (Math.abs(1 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 1); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.DARK); - }); - } - - if (Math.abs(2 - currentPosition) <= 1) { - mapFragment = (SupportMapFragment) adapter.instantiateItem(viewPager, 2); - mapFragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.SATELLITE); - }); - } - } - - static class MapFragmentAdapter extends FragmentStatePagerAdapter { - - private static int NUM_ITEMS = 3; - - MapFragmentAdapter(FragmentManager fragmentManager) { - super(fragmentManager); - } - - @Override - public int getCount() { - return NUM_ITEMS; - } - - @Override - public Fragment getItem(int position) { - SupportMapFragment fragment = null; - MapboxMapOptions options = new MapboxMapOptions(); - options.textureMode(true); - - switch (position) { - case 0: - options.camera(new CameraPosition.Builder().target(new LatLng(34.920526, 102.634774)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.MAPBOX_STREETS); - }); - break; - case 1: - options.camera(new CameraPosition.Builder().target(new LatLng(62.326440, 92.764913)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.DARK); - }); - break; - case 2: - options.camera(new CameraPosition.Builder().target(new LatLng(-25.007786, 133.623852)).zoom(3).build()); - fragment = SupportMapFragment.newInstance(options); - fragment.getMapAsync(mapboxMap -> { - mapboxMap.setStyle(Style.SATELLITE); - }); - break; - } - return fragment; - } - - @Override - public CharSequence getPageTitle(int position) { - return "Page " + position; - } - } -} - diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt new file mode 100644 index 0000000000..77e2e1370d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/fragment/ViewPagerActivity.kt @@ -0,0 +1,109 @@ +package com.mapbox.mapboxsdk.testapp.activity.fragment + +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentStatePagerAdapter +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.camera.CameraPosition +import com.mapbox.mapboxsdk.geometry.LatLng +import com.mapbox.mapboxsdk.maps.MapboxMapOptions +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.maps.SupportMapFragment +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_viewpager.* + +/** + * Test activity showcasing using the Android SDK ViewPager API to show MapFragments. + */ +class ViewPagerActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_viewpager) + viewPager.adapter = MapFragmentAdapter(supportFragmentManager) + } + + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) + + val currentPosition = viewPager.currentItem + var mapFragment: SupportMapFragment + + if (Math.abs(0 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 0) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + } + + if (Math.abs(1 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 1) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) } + } + + if (Math.abs(2 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 2) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + + if (Math.abs(3 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 3) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + + if (Math.abs(4 - currentPosition) <= 1) { + mapFragment = viewPager.adapter?.instantiateItem(viewPager, 4) as SupportMapFragment + mapFragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + } + + internal class MapFragmentAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) { + + override fun getCount(): Int { + return NUM_ITEMS + } + + override fun getItem(position: Int): Fragment? { + var fragment: SupportMapFragment? = null + val options = MapboxMapOptions() + options.textureMode(true) + + when (position) { + 0 -> { + options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + } + 1 -> { + options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) } + } + 2 -> { + options.camera(CameraPosition.Builder().target(LatLng(-25.007786, 133.623852)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) } + } + 3 -> { + options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.LIGHT) } + } + 4 -> { + options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build()) + fragment = SupportMapFragment.newInstance(options) + fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.TRAFFIC_NIGHT) } + } + } + return fragment + } + + override fun getPageTitle(position: Int): CharSequence? { + return "Page $position" + } + + companion object { + + private val NUM_ITEMS = 5 + } + } +} 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 deleted file mode 100644 index c1697ab960..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.imagegenerator; - -import android.graphics.Bitmap; -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.AppCompatActivity; -import android.view.View; -import android.widget.ImageView; -import android.widget.Toast; - -import com.mapbox.mapboxsdk.maps.Style; -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; - -import timber.log.Timber; - -/** - * 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; - private MapboxMap mapboxMap; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_snapshot); - - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(this); - } - - @Override - public void onMapReady(@NonNull MapboxMap map) { - mapboxMap = map; - mapboxMap.setStyle(new Style.Builder().fromUrl(Style.OUTDOORS)); - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - if (fab != null) { - fab.setColorFilter(ContextCompat.getColor(SnapshotActivity.this, R.color.primary)); - fab.setOnClickListener(this); - } - } - - @Override - public void onClick(View view) { - final long startTime = System.nanoTime(); - mapboxMap.snapshot(snapshot -> { - long endTime = System.nanoTime(); - long duration = (long) ((endTime - startTime) / 1e6); - ImageView snapshotView = (ImageView) findViewById(R.id.imageView); - snapshotView.setImageBitmap(snapshot); - Toast.makeText( - SnapshotActivity.this, - String.format(Locale.getDefault(), "Snapshot taken in %d ms", duration), - Toast.LENGTH_LONG).show(); - }); - } - - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - - @Override - protected void onResume() { - super.onResume(); - mapView.onResume(); - } - - @Override - protected void onPause() { - super.onPause(); - mapboxMap.snapshot(new MapboxMap.SnapshotReadyCallback() { - @Override - public void onSnapshotReady(Bitmap snapshot) { - Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358"); - } - }); - mapView.onPause(); - } - - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - mapView.onSaveInstanceState(outState); - } - - @Override - public void onLowMemory() { - super.onLowMemory(); - mapView.onLowMemory(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - mapView.onDestroy(); - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt new file mode 100644 index 0000000000..51b1c08ba5 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/imagegenerator/SnapshotActivity.kt @@ -0,0 +1,80 @@ +package com.mapbox.mapboxsdk.testapp.activity.imagegenerator + +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.MapboxMap +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_snapshot.* +import timber.log.Timber + +/** + * Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map. + */ +class SnapshotActivity : AppCompatActivity(), OnMapReadyCallback { + + private lateinit var mapboxMap: MapboxMap + + private val idleListener = object : MapView.OnDidBecomeIdleListener { + override fun onDidBecomeIdle() { + mapView.removeOnDidBecomeIdleListener(this) + mapboxMap.snapshot { snapshot -> + imageView.setImageBitmap(snapshot) + mapView.addOnDidBecomeIdleListener(this) + } + } + } + + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_snapshot) + mapView.onCreate(savedInstanceState) + mapView.getMapAsync(this) + } + + override fun onMapReady(map: MapboxMap) { + mapboxMap = map + mapboxMap.setStyle(Style.Builder().fromUrl(Style.OUTDOORS)) { mapView.addOnDidBecomeIdleListener(idleListener) } + } + + override fun onStart() { + super.onStart() + mapView.onStart() + } + + override fun onResume() { + super.onResume() + mapView.onResume() + } + + override fun onPause() { + super.onPause() + mapboxMap.snapshot { + Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358") + } + mapView.onPause() + } + + override fun onStop() { + super.onStop() + mapView.onStop() + } + + public override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + mapView.onSaveInstanceState(outState) + } + + override fun onLowMemory() { + super.onLowMemory() + mapView.onLowMemory() + } + + public override fun onDestroy() { + super.onDestroy() + mapView.removeOnDidBecomeIdleListener(idleListener) + mapView.onDestroy() + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt new file mode 100644 index 0000000000..5acf356696 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/GLSurfaceRecyclerViewActivity.kt @@ -0,0 +1,155 @@ +package com.mapbox.mapboxsdk.testapp.activity.maplayout + +import android.annotation.SuppressLint +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.TextView +import com.mapbox.mapboxsdk.maps.MapView +import com.mapbox.mapboxsdk.maps.Style +import com.mapbox.mapboxsdk.testapp.R +import kotlinx.android.synthetic.main.activity_recyclerview.* + +/** + * TestActivity showcasing how to integrate a GLSurfaceView MapView in a RecyclerView. + * <p> + * It requires calling the correct lifecycle methods when detaching and attaching the View to + * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow. + * </p> + */ +@SuppressLint("ClickableViewAccessibility") +open class GLSurfaceRecyclerViewActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_recyclerview) + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this), savedInstanceState) + } + + override fun onSaveInstanceState(outState: Bundle?) { + super.onSaveInstanceState(outState) + // to save state, we need to call MapView#onSaveInstanceState + (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState) + } + + override fun onLowMemory() { + super.onLowMemory() + // to release memory, we need to call MapView#onLowMemory + (recyclerView.adapter as ItemAdapter).onLowMemory() + } + + override fun onDestroy() { + super.onDestroy() + // to perform cleanup, we need to call MapView#onDestroy + (recyclerView.adapter as ItemAdapter).onDestroy() + } + + open fun getMapItemLayoutId(): Int { + return R.layout.item_map_gl + } + + class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { + + private val items = listOf( + "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten", + "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", + "nineteen", "twenty", "twenty-one" + ) + + private var mapHolder: MapHolder? = null + + companion object { + const val TYPE_MAP = 0 + const val TYPE_TEXT = 1 + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return if (viewType == TYPE_MAP) { + val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView + mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } + mapHolder = MapHolder(mapView, savedInstanceState) + return mapHolder as MapHolder + } else { + TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView) + } + } + + override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { + super.onViewAttachedToWindow(holder) + if (holder is MapHolder) { + val mapView = holder.mapView + mapView.onStart() + mapView.onResume() + } + } + + override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { + super.onViewDetachedFromWindow(holder) + if (holder is MapHolder) { + val mapView = holder.mapView + mapView.onPause() + mapView.onStop() + } + } + + override fun getItemCount(): Int { + return items.count() + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder.itemViewType == TYPE_TEXT) { + val textHolder = holder as TextHolder + textHolder.bind(items[position] as String) + } + } + + override fun getItemViewType(position: Int): Int { + return if (items[position] is MapItem) { + TYPE_MAP + } else { + TYPE_TEXT + } + } + + fun onSaveInstanceState(savedInstanceState: Bundle?) { + savedInstanceState?.let { + mapHolder?.mapView?.onSaveInstanceState(it) + } + } + + fun onLowMemory() { + mapHolder?.mapView?.onLowMemory() + } + + fun onDestroy() { + mapHolder?.mapView?.let { + it.onPause() + it.onStop() + it.onDestroy() + } + } + + class MapItem + class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) { + init { + mapView.onCreate(bundle) + mapView.setOnTouchListener { view, motionEvent -> + // Disallow the touch request for recyclerView scroll + view.parent.requestDisallowInterceptTouchEvent(true) + mapView.onTouchEvent(motionEvent) + true + } + } + } + + class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { + fun bind(item: String) { + textView.text = item + } + } + } +} 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 c9a9377885..18092ce372 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 @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk.testapp.activity.maplayout; -import android.app.Dialog; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -17,9 +16,6 @@ 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 { @@ -64,23 +60,6 @@ public class MapInDialogActivity extends AppCompatActivity { mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.OUTDOORS)); } - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new Dialog(getActivity(), getTheme()) { - @Override - public void dismiss() { - if (mapView != null && !mapView.isDestroyed()) { - mapView.onPause(); - mapView.onStop(); - mapView.onDestroy(); - mapView = null; - } - super.dismiss(); - } - }; - } - @Override public void onStart() { super.onStart(); @@ -96,25 +75,20 @@ public class MapInDialogActivity extends AppCompatActivity { @Override public void onPause() { super.onPause(); - if (mapView != null) { - mapView.onPause(); - } + mapView.onPause(); } @Override public void onStop() { super.onStop(); - if (mapView != null) { - mapView.onStop(); - } + mapView.onStop(); } @Override public void onDestroyView() { super.onDestroyView(); - if (mapView != null) { - mapView.onDestroy(); - } + mapView.onDestroy(); + mapView = null; } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt deleted file mode 100644 index 9989d1b137..0000000000 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/RecyclerViewActivity.kt +++ /dev/null @@ -1,151 +0,0 @@ -package com.mapbox.mapboxsdk.testapp.activity.maplayout - -import android.annotation.SuppressLint -import android.os.Bundle -import android.support.v7.app.AppCompatActivity -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.TextView -import com.mapbox.mapboxsdk.maps.MapView -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback -import com.mapbox.mapboxsdk.maps.Style -import com.mapbox.mapboxsdk.testapp.R -import kotlinx.android.synthetic.main.activity_recyclerview.* - -/** - * TestActivity showcasing how to integrate a MapView in a RecyclerView. - * <p> - * It requires calling the correct lifecycle methods when detaching and attaching the View to - * the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow. - * </p> - */ -@SuppressLint("ClickableViewAccessibility") -class RecyclerViewActivity : AppCompatActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_recyclerview) - recyclerView.layoutManager = LinearLayoutManager(this) - recyclerView.adapter = ItemAdapter(LayoutInflater.from(this), savedInstanceState) - } - - override fun onSaveInstanceState(outState: Bundle?) { - super.onSaveInstanceState(outState) - // to save state, we need to call MapView#onSaveInstanceState - (recyclerView.adapter as ItemAdapter).onSaveInstanceState(outState) - } - - override fun onLowMemory() { - super.onLowMemory() - // to release memory, we need to call MapView#onLowMemory - (recyclerView.adapter as ItemAdapter).onLowMemory() - } - - override fun onDestroy() { - super.onDestroy() - // to perform cleanup, we need to call MapView#onDestroy - (recyclerView.adapter as ItemAdapter).onDestroy() - } - - class ItemAdapter(private val inflater: LayoutInflater, val savedInstanceState: Bundle?) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { - - private val items = listOf( - "one", "two", "three", MapItem(), "four", "five", "six", "seven", "eight", "nine", "ten", - "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", - "nineteen", "twenty", "twenty-one" - ) - - private var mapHolder: MapHolder? = null - - companion object { - const val TYPE_MAP = 0 - const val TYPE_TEXT = 1 - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return if (viewType == TYPE_MAP) { - val mapView = inflater.inflate(R.layout.item_map, parent, false) as MapView - mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) } - mapHolder = MapHolder(mapView, savedInstanceState) - return mapHolder as MapHolder - } else { - TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView) - } - } - - override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { - super.onViewAttachedToWindow(holder) - if (holder is MapHolder) { - val mapView = holder.mapView - mapView.onStart() - mapView.onResume() - } - } - - override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) { - super.onViewDetachedFromWindow(holder) - if (holder is MapHolder) { - val mapView = holder.mapView - mapView.onPause() - mapView.onStop() - } - } - - override fun getItemCount(): Int { - return items.count() - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - if (holder.itemViewType == TYPE_TEXT) { - val textHolder = holder as TextHolder - textHolder.bind(items[position] as String) - } - } - - override fun getItemViewType(position: Int): Int { - return if (items[position] is MapItem) { - TYPE_MAP - } else { - TYPE_TEXT - } - } - - fun onSaveInstanceState(savedInstanceState: Bundle?){ - savedInstanceState?.let { - mapHolder?.mapView?.onSaveInstanceState(it) - } - } - - fun onLowMemory() { - mapHolder?.mapView?.onLowMemory() - } - - fun onDestroy() { - mapHolder?.mapView?.let { - it.onPause() - it.onStop() - it.onDestroy() - } - } - - class MapItem - class MapHolder(val mapView: MapView, bundle: Bundle?) : RecyclerView.ViewHolder(mapView) { - init { - mapView.onCreate(bundle) - mapView.setOnTouchListener { view, motionEvent -> - // Disallow the touch request for recyclerView scroll - view.parent.requestDisallowInterceptTouchEvent(true) - mapView.onTouchEvent(motionEvent) - true - } - } - } - class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) { - fun bind(item: String) { - textView.text = item - } - } - } -} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt new file mode 100644 index 0000000000..895389bc1e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/TextureRecyclerViewActivity.kt @@ -0,0 +1,15 @@ +package com.mapbox.mapboxsdk.testapp.activity.maplayout + +import android.annotation.SuppressLint +import com.mapbox.mapboxsdk.testapp.R + +/** + * TestActivity showcasing how to integrate a TexureView MapView in a RecyclerView. + */ +@SuppressLint("ClickableViewAccessibility") +class TextureRecyclerViewActivity : GLSurfaceRecyclerViewActivity() { + + override fun getMapItemLayoutId() : Int{ + return R.layout.item_map_texture + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java new file mode 100644 index 0000000000..285d7bc6c8 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/telemetry/PerformanceMeasurementActivity.java @@ -0,0 +1,187 @@ +package com.mapbox.mapboxsdk.testapp.activity.telemetry; + +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.util.DisplayMetrics; +import android.view.Display; +import android.view.WindowManager; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.module.http.HttpRequestUtil; +import com.mapbox.mapboxsdk.testapp.R; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import okhttp3.Call; +import okhttp3.EventListener; +import okhttp3.OkHttpClient; +import timber.log.Timber; + +/** + * Test activity showcasing gathering performance measurement data. + */ +public class PerformanceMeasurementActivity extends AppCompatActivity { + + private MapView mapView; + + private Map<String, Long> startTimes = new HashMap<>(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_map_simple); + mapView = findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.eventListener(new EventListener() { + + @Override + public void callStart(Call call) { + String url = call.request().url().toString(); + startTimes.put(url, System.nanoTime()); + super.callStart(call); + Timber.e("callStart: %s", url); + } + + @Override + public void callEnd(Call call) { + String url = call.request().url().toString(); + Timber.e("callEnd: %s", url); + Long start = startTimes.get(url); + if (start != null) { + long elapsed = System.nanoTime() - start; + triggerPerformanceEvent(url.substring(0, url.indexOf('?')), elapsed); + startTimes.remove(start); + Timber.e("callEnd: %s took %d", url, elapsed); + } + super.callEnd(call); + } + }); + HttpRequestUtil.setOkHttpClient(builder.build()); + + mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle( + new Style.Builder().fromUrl(Style.MAPBOX_STREETS))); + } + + + @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 + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + protected void onDestroy() { + + startTimes.clear(); + + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + private void triggerPerformanceEvent(String style, long elapsed) { + + List<Attribute<String>> attributes = new ArrayList<>(); + attributes.add( + new Attribute<>("style_id", style)); + attributes.add( + new Attribute<>("test_perf_event", "true")); + + List<Attribute<Long>> counters = new ArrayList(); + counters.add(new Attribute<>("elapsed", elapsed)); + + + JsonObject metaData = new JsonObject(); + metaData.addProperty("os", "android"); + metaData.addProperty("manufacturer", Build.MANUFACTURER); + metaData.addProperty("brand", Build.BRAND); + metaData.addProperty("device", Build.MODEL); + metaData.addProperty("version", Build.VERSION.RELEASE); + metaData.addProperty("abi", Build.CPU_ABI); + metaData.addProperty("country", Locale.getDefault().getISO3Country()); + metaData.addProperty("ram", getRam()); + metaData.addProperty("screenSize", getWindowSize()); + + Gson gson = new Gson(); + + Bundle bundle = new Bundle(); + bundle.putString("attributes", gson.toJson(attributes)); + bundle.putString("counters", gson.toJson(counters)); + bundle.putString("metadata", metaData.toString()); + + Mapbox.getTelemetry().onPerformanceEvent(bundle); + } + + private static String getRam() { + ActivityManager actManager = + (ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + actManager.getMemoryInfo(memInfo); + return String.valueOf(memInfo.totalMem); + } + + private static String getWindowSize() { + WindowManager windowManager = + (WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + int width = metrics.widthPixels; + int height = metrics.heightPixels; + + return "{" + width + "," + height + "}"; + } + + private class Attribute<T> { + private String name; + private T value; + + Attribute(String name, T value) { + this.name = name; + this.value = value; + } + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml index b6b672cf73..10c11a9320 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_backstack_fragment.xml @@ -10,6 +10,7 @@ <Button android:layout_width="match_parent" android:layout_height="58dp" android:id="@+id/button" + android:contentDescription="btn_change_fragment" android:text="Replace with empty fragment"/> </FrameLayout>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml new file mode 100644 index 0000000000..4c88a87703 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_pixel_test.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<FrameLayout + 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"> + + <com.mapbox.mapboxsdk.maps.MapView + android:layout_gravity="center" + android:id="@id/mapView" + app:mapbox_cameraZoom="1" + android:layout_width="1080px" + android:layout_height="1920px" + app:mapbox_pixelRatio="1"/> + +</FrameLayout> 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 53345571b4..f0787ecad9 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_snapshot.xml @@ -1,7 +1,6 @@ <?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"> @@ -27,15 +26,4 @@ </LinearLayout> - <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_a_photo_black" - app:backgroundTint="@android:color/white"/> - </RelativeLayout> 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 3edaff6985..516bf60b6b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_viewpager.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent"> <com.mapbox.mapboxsdk.testapp.view.MapViewPager - android:id="@+id/viewpager" + android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent"> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml new file mode 100644 index 0000000000..850399e355 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_gl.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<com.mapbox.mapboxsdk.maps.MapView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@id/mapView" + android:layout_width="match_parent" + android:layout_height="256dp" + app:mapbox_cameraTargetLat="45.38301927899065" + app:mapbox_cameraTargetLng="8.63525390625" + app:mapbox_cameraZoom="7"/> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml index 3224b73477..3224b73477 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/item_map_texture.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml index a4403a34f7..2c34a59327 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/categories.xml @@ -15,4 +15,6 @@ <string name="category_storage">Storage</string> <string name="category_textureview">Texture View</string> <string name="category_location">Location</string> + <string name="category_integration">_Integration</string> + <string name="category_telemetry">Telemetry</string> </resources>
\ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml index 21ebeaabd5..778805b3b3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml @@ -78,6 +78,8 @@ <string name="description_location_fragment">Uses LocationComponent in a Fragment</string> <string name="description_location_manual">Force location updates and don\'t rely on the engine</string> <string name="description_location_activation_builder">Use LocationComponentActivationOptions to set options</string> - <string name="description_recyclerview">Show a MapView as a recyclerView item</string> + <string name="description_recyclerview_textureview">Show a TextureView MapView as a recyclerView item</string> + <string name="description_recyclerview_glsurfaceview">Show a GLSurfaceView MapView as a recyclerView item</string> <string name="description_nested_viewpager">Show a MapView inside a viewpager inside a recyclerView</string> + <string name="description_performance_measurement">Show the use PerformanceEvent for performance measurements</string> </resources> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml index 26f56f29b1..12c82bf21a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml @@ -78,6 +78,8 @@ <string name="activity_location_fragment">Location Fragment</string> <string name="activity_location_manual">Manual Location updates</string> <string name="activity_location_activation_builder">Build Location Activation</string> - <string name="activity_recyclerview">RecyclerView</string> + <string name="activity_recyclerview_textureview">RecyclerView TextureView</string> + <string name="activity_recyclerview_glsurfaceview">RecyclerView GLSurfaceView</string> <string name="activity_nested_viewpager">Nested ViewPager</string> + <string name="activity_performance_measurement">Performance Measurement</string> </resources>
\ No newline at end of file diff --git a/platform/android/build.gradle b/platform/android/build.gradle index 5334c93ce9..97f3037afb 100644 --- a/platform/android/build.gradle +++ b/platform/android/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath dependenciesList.bintrayPlugin classpath dependenciesList.artifactoryPlugin classpath dependenciesList.androidPublishPlugin + classpath dependenciesList.jacocoPlugin } } diff --git a/platform/android/gradle/android-nitpick.gradle b/platform/android/gradle/android-nitpick.gradle index f8e4a47b0b..32539270f5 100644 --- a/platform/android/gradle/android-nitpick.gradle +++ b/platform/android/gradle/android-nitpick.gradle @@ -17,6 +17,8 @@ task androidNitpick { verifyVendorSubmodulePin(MAPBOX_JAVA_DIR, MAPBOX_JAVA_TAG_PREFIX, versions.mapboxServices) verifyVendorSubmodulePin(MAPBOX_TELEMETRY_DIR, MAPBOX_TELEMETRY_TAG_PREFIX, versions.mapboxTelemetry) verifyVendorSubmodulePin(MAPBOX_GESTURES_DIR, MAPBOX_GESTURES_TAG_PREFIX, versions.mapboxGestures) + + verifyLicenseGeneration() } } @@ -51,4 +53,12 @@ private def verifyVendorSubmodulePin(def dir, def prefix, def version) { "If you've bumped the pin, make sure to verify the version tag prefix in the android-nitpick.gradle file.") } output.close() +} + +private def verifyLicenseGeneration() { + println "Verify license generation with git diff..." + exec { + workingDir = "${rootDir}" + commandLine "python", "scripts/validate-license.py" + } }
\ No newline at end of file diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 600901ca76..1d17e7f83d 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { versions = [ mapboxServices : '4.3.0', - mapboxTelemetry : '4.2.0', + mapboxTelemetry : '4.3.0', mapboxGestures : '0.4.0', supportLib : '27.1.1', constraintLayout: '1.1.2', @@ -29,7 +29,8 @@ ext { androidPublish : '3.6.2', lint : '26.1.4', gms : '16.0.0', - reLinker : '1.3.1' + reLinker : '1.3.1', + jacoco : '0.8.3' ] dependenciesList = [ @@ -72,6 +73,7 @@ ext { bintrayPlugin : "com.jfrog.bintray.gradle:gradle-bintray-plugin:${versions.bintray}", artifactoryPlugin : "org.jfrog.buildinfo:build-info-extractor-gradle:${versions.artifactory}", androidPublishPlugin : "digital.wup:android-maven-publish:${versions.androidPublish}", + jacocoPlugin : "org.jacoco:org.jacoco.core:${versions.jacoco}", lint : "com.android.tools.lint:lint:${versions.lint}", lintApi : "com.android.tools.lint:lint-api:${versions.lint}", diff --git a/platform/android/gradle/jacoco-report.gradle b/platform/android/gradle/jacoco-report.gradle new file mode 100644 index 0000000000..e50facb683 --- /dev/null +++ b/platform/android/gradle/jacoco-report.gradle @@ -0,0 +1,33 @@ +apply plugin: 'jacoco' +apply from: "${rootDir}/gradle/dependencies.gradle" + +jacoco { + toolVersion = versions.jacoco +} + +task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { + group = "Reporting" + description = "Combine code coverage to unified report." + + reports { + xml.enabled = true + html.enabled = true + } + + def fileExcludes = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] + def debugTree = fileTree(dir: "${project.buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes", excludes: fileExcludes) + def mainSrc = "${project.projectDir}/src/main/java" + println(mainSrc) + def ecSrc = fileTree(dir: "$project.buildDir", include: "**/*.ec") + def execSrc = fileTree(dir: "$project.buildDir", include: "**/*.exec") + + doFirst { + def files = files([ecSrc, execSrc]).files + println "Creating Jacoco Report for ${files.size()} coverage files" + files.each { file -> println file } + } + + sourceDirectories = files([mainSrc]) + classDirectories = files([debugTree]) + executionData = files([ecSrc, execSrc]) +}
\ No newline at end of file diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json index 9e0a1d154f..a6070edccf 100644 --- a/platform/android/scripts/exclude-activity-gen.json +++ b/platform/android/scripts/exclude-activity-gen.json @@ -48,5 +48,7 @@ "EspressoTestActivity", "ChangeResourcesCachePathActivity", "EspressoTestActivity", - "FragmentBackStackActivity" + "FragmentBackStackActivity", + "ChildFragmentMapInDialogActivity", + "PerformanceMeasurementActivity" ] diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 56e7511362..688a3aa527 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -197,7 +197,12 @@ global.defaultValueJava = function(property) { case 'array': switch (property.value) { case 'string': - return '[' + property['default'] + "]"; + case 'enum': + if (property['default'] !== undefined) { + return '[' + property['default'] + ']'; + } else { + return 'new String[0]'; + } case 'number': var result ='new Float[] {'; for (var i = 0; i < property.length; i++) { diff --git a/platform/android/scripts/parse-jacoco-report.py b/platform/android/scripts/parse-jacoco-report.py new file mode 100755 index 0000000000..4d06fda6cc --- /dev/null +++ b/platform/android/scripts/parse-jacoco-report.py @@ -0,0 +1,31 @@ +#!/usr/bin/python + +import os +import re +from io import open + +reportPath = os.getcwd() + "/platform/android/MapboxGLAndroidSDK/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +with open(reportPath, 'r', encoding='utf-8') as jacocoReport: + line = jacocoReport.readline().strip() + + # find the last INSTRUCTION coverage report which is a sum of all separate ones + instructionIndex = line.rfind('type="INSTRUCTION"') + startIndex = line.find('missed', instructionIndex) + endIndex = line.find('/>', startIndex) + + # find the missed and covered lines counts + numbers = re.match(r'missed="(\d+)" covered="(\d+)"', line[startIndex:endIndex]) + missed = int(numbers.group(1)) + covered = int(numbers.group(2)) + + # calculate the code coverage percentage + percentage = round(covered * 100.0 / (missed + covered), 2) + print("Android tests code coverage: %s%%" % (str(percentage))) + + # invoke the script that send the data to s3 + testEnvironment = "LOCAL" + if os.environ.get('IS_LOCAL_DEVELOPMENT').lower()=='false': + testEnvironment = "CI" + + cmd = os.getcwd() + ("/scripts/code-coverage.sh %.2f %s %s" % (percentage, "Android", testEnvironment)) + os.system(cmd) diff --git a/platform/android/scripts/validate-license.py b/platform/android/scripts/validate-license.py new file mode 100644 index 0000000000..365d7ac265 --- /dev/null +++ b/platform/android/scripts/validate-license.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +from subprocess import call +from subprocess import Popen, PIPE +import sys + +## Run license generation +call('cd ../../ && make android-license', shell=True) + +## Git diff changes +p = Popen(['git', 'diff', '--name-only', 'LICENSE.md'], stdin=PIPE, stdout=PIPE, stderr=PIPE) +output, err = p.communicate(b"input data that is passed to subprocess' stdin") +if "platform/android/LICENSE.md" in output: + raise ValueError("""An error ocurred while validating the license generation. + Changes were detected to the license generation output + but weren't commited. Run make android-license and + commit the changeset to make this validation pass.""")
\ No newline at end of file diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index 4def670f3c..839e6e84dc 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -88,6 +88,17 @@ struct Converter<jni::Local<jni::Object<>>, T, typename std::enable_if_t<std::is } }; +template <class T> +struct Converter<jni::Local<jni::Object<>>, std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>> { + Result<jni::Local<jni::Object<>>> operator()(jni::JNIEnv& env, const std::vector<T>& value) const { + auto result = jni::Array<jni::String>::New(env, value.size()); + for (std::size_t i = 0; i < value.size(); ++i) { + result.Set(env, i, jni::Make<jni::String>(env, Enum<T>::toString(value.at(i)))); + } + return result; + } +}; + } // namespace conversion } // namespace android } // namespace mbgl diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 4cfb545b84..41081cd0fb 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -3,6 +3,7 @@ #include <mbgl/actor/actor.hpp> #include <mbgl/actor/scheduler.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/resource_transform.hpp> #include <mbgl/util/logging.hpp> @@ -11,6 +12,14 @@ #include "asset_manager_file_source.hpp" namespace mbgl { + +std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) { + auto* assetFileSource = reinterpret_cast<AssetManagerFileSource*>(options.platformContext()); + auto fileSource = std::make_shared<DefaultFileSource>(options.cachePath(), std::unique_ptr<AssetManagerFileSource>(assetFileSource)); + fileSource->setAccessToken(options.accessToken()); + return fileSource; +} + namespace android { // FileSource // @@ -22,15 +31,13 @@ FileSource::FileSource(jni::JNIEnv& _env, std::string path = jni::Make<std::string>(_env, _cachePath); mapbox::sqlite::setTempPath(path); - // Create a core default file source - fileSource = std::make_unique<mbgl::DefaultFileSource>( - path + DATABASE_FILE, - std::make_unique<AssetManagerFileSource>(_env, assetManager)); + resourceOptions + .withAccessToken(accessToken ? jni::Make<std::string>(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE) + .withPlatformContext(reinterpret_cast<void*>(new AssetManagerFileSource(_env, assetManager))); - // Set access token - if (accessToken) { - fileSource->setAccessToken(jni::Make<std::string>(_env, accessToken)); - } + // Create a core default file source + fileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(resourceOptions)); } FileSource::~FileSource() { @@ -110,10 +117,10 @@ FileSource* FileSource::getNativePeer(jni::JNIEnv& env, const jni::Object<FileSo return reinterpret_cast<FileSource *>(jFileSource.Get(env, field)); } -mbgl::DefaultFileSource& FileSource::getDefaultFileSource(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) { +mbgl::ResourceOptions FileSource::getSharedResourceOptions(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) { FileSource* fileSource = FileSource::getNativePeer(env, jFileSource); assert(fileSource != nullptr); - return *fileSource->fileSource; + return fileSource->resourceOptions.clone(); } void FileSource::registerNative(jni::JNIEnv& env) { diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp index 575702120e..3001a5e0f0 100644 --- a/platform/android/src/file_source.hpp +++ b/platform/android/src/file_source.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include "asset_manager.hpp" @@ -49,15 +50,16 @@ public: static FileSource* getNativePeer(jni::JNIEnv&, const jni::Object<FileSource>&); - static mbgl::DefaultFileSource& getDefaultFileSource(jni::JNIEnv&, const jni::Object<FileSource>&); + static mbgl::ResourceOptions getSharedResourceOptions(jni::JNIEnv&, const jni::Object<FileSource>&); static void registerNative(jni::JNIEnv&); private: const std::string DATABASE_FILE = "/mbgl-offline.db"; optional<int> activationCounter; + mbgl::ResourceOptions resourceOptions; std::unique_ptr<Actor<ResourceTransform>> resourceTransform; - std::unique_ptr<mbgl::DefaultFileSource> fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 3e5b99605e..57265cebb1 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -1,13 +1,15 @@ #pragma once +#include <mbgl/actor/actor_ref.hpp> #include <mbgl/actor/scheduler.hpp> #include <mbgl/util/image.hpp> +#include <mbgl/util/optional.hpp> #include <memory> +#include <mutex> #include <utility> #include <jni/jni.hpp> -#include <mbgl/storage/default_file_source.hpp> namespace mbgl { diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 3a4e2014ba..e74e4c3bbc 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -13,6 +13,7 @@ #include <jni/jni.hpp> +#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/math/minmax.hpp> #include <mbgl/util/constants.hpp> @@ -74,24 +75,22 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env, return; } - // Get native peer for file source - mbgl::FileSource& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource); - // Create a renderer frontend rendererFrontend = std::make_unique<AndroidRendererFrontend>(mapRenderer); // Create Map options MapOptions options; options.withMapMode(MapMode::Continuous) + .withSize(mbgl::Size{ static_cast<uint32_t>(width), static_cast<uint32_t>(height) }) + .withPixelRatio(pixelRatio) .withConstrainMode(ConstrainMode::HeightOnly) .withViewportMode(ViewportMode::Default) .withCrossSourceCollisions(_crossSourceCollisions); // Create the core map - map = std::make_unique<mbgl::Map>(*rendererFrontend, *this, - mbgl::Size{ static_cast<uint32_t>(width), - static_cast<uint32_t>(height) }, pixelRatio, - fileSource, *threadPool, options); + map = std::make_unique<mbgl::Map>( + *rendererFrontend, *this, *threadPool, options, + mbgl::android::FileSource::getSharedResourceOptions(_env, jFileSource)); } /** diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index d695a91ce0..903543e5d1 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -6,7 +6,6 @@ #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 "annotation/marker.hpp" diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 968c33b644..54b1142845 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -10,20 +10,19 @@ namespace android { // OfflineManager // OfflineManager::OfflineManager(jni::JNIEnv& env, const jni::Object<FileSource>& jFileSource) - : fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) { -} + : fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} OfflineManager::~OfflineManager() {} void OfflineManager::setOfflineMapboxTileCountLimit(jni::JNIEnv&, jni::jlong limit) { - fileSource.setOfflineMapboxTileCountLimit(limit); + fileSource->setOfflineMapboxTileCountLimit(limit); } void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, const jni::Object<FileSource>& jFileSource_, const jni::Object<ListOfflineRegionsCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); - fileSource.listOfflineRegions([ + 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::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -59,7 +58,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); // Create region - fileSource.createOfflineRegion(definition, metadata, [ + 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::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -86,7 +85,7 @@ void OfflineManager::mergeOfflineRegions(jni::JNIEnv& env_, const jni::Object<Fi auto globalFilesource = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, jFileSource_); auto path = jni::Make<std::string>(env_, jString_); - fileSource.mergeOfflineRegions(path, [ + fileSource->mergeOfflineRegions(path, [ //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::make_shared<decltype(globalCallback)>(std::move(globalCallback)), jFileSource = std::make_shared<decltype(globalFilesource)>(std::move(globalFilesource)) @@ -226,7 +225,7 @@ void OfflineManager::putResourceWithUrl(jni::JNIEnv& env, response.expires = Timestamp(mbgl::Seconds(expires)); } - fileSource.put(resource, response); + fileSource->put(resource, response); } } // namespace android diff --git a/platform/android/src/offline/offline_manager.hpp b/platform/android/src/offline/offline_manager.hpp index f8d57b88da..d0b637b900 100644 --- a/platform/android/src/offline/offline_manager.hpp +++ b/platform/android/src/offline/offline_manager.hpp @@ -1,7 +1,5 @@ #pragma once - -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/offline.hpp> #include <jni/jni.hpp> @@ -10,8 +8,12 @@ #include "offline_region_definition.hpp" #include "../java_types.hpp" +#include <memory> namespace mbgl { + +class DefaultFileSource; + namespace android { class OfflineManager { @@ -85,7 +87,7 @@ public: private: - mbgl::DefaultFileSource& fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; } // namespace android diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index 1cd73a7c76..e0f28631b4 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -14,8 +14,8 @@ namespace android { // OfflineRegion // OfflineRegion::OfflineRegion(jni::JNIEnv& env, jni::jlong offlineRegionPtr, const jni::Object<FileSource>& jFileSource) - : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)), - fileSource(mbgl::android::FileSource::getDefaultFileSource(env, jFileSource)) {} + : region(reinterpret_cast<mbgl::OfflineRegion *>(offlineRegionPtr)) + , fileSource(std::static_pointer_cast<DefaultFileSource>(mbgl::FileSource::getSharedFileSource(FileSource::getSharedResourceOptions(env, jFileSource)))) {} OfflineRegion::~OfflineRegion() {} @@ -62,7 +62,7 @@ void OfflineRegion::setOfflineRegionObserver(jni::JNIEnv& env_, const jni::Objec }; // Set the observer - fileSource.setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback))); + fileSource->setOfflineRegionObserver(*region, std::make_unique<Observer>(jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback))); } void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState) { @@ -80,13 +80,13 @@ void OfflineRegion::setOfflineRegionDownloadState(jni::JNIEnv&, jni::jint jState return; } - fileSource.setOfflineRegionDownloadState(*region, state); + fileSource->setOfflineRegionDownloadState(*region, state); } void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object<OfflineRegionStatusCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.getOfflineRegionStatus(*region, [ + fileSource->getOfflineRegionStatus(*region, [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) mutable { @@ -104,7 +104,7 @@ void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, const jni::Object< void OfflineRegion::deleteOfflineRegion(jni::JNIEnv& env_, const jni::Object<OfflineRegionDeleteCallback>& callback_) { auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.deleteOfflineRegion(std::move(*region), [ + fileSource->deleteOfflineRegion(std::move(*region), [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](std::exception_ptr error) mutable { @@ -123,7 +123,7 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, const jni::Ar auto metadata = OfflineRegion::metadata(env_, jMetadata); auto globalCallback = jni::NewGlobal<jni::EnvAttachingDeleter>(env_, callback_); - fileSource.updateOfflineMetadata(region->getID(), metadata, [ + fileSource->updateOfflineMetadata(region->getID(), metadata, [ //Ensure the object is not gc'd in the meanwhile callback = std::make_shared<decltype(globalCallback)>(std::move(globalCallback)) ](mbgl::expected<mbgl::OfflineRegionMetadata, std::exception_ptr> data) mutable { diff --git a/platform/android/src/offline/offline_region.hpp b/platform/android/src/offline/offline_region.hpp index 49fa0c8ff8..4618e1abbd 100644 --- a/platform/android/src/offline/offline_region.hpp +++ b/platform/android/src/offline/offline_region.hpp @@ -74,7 +74,7 @@ public: private: std::unique_ptr<mbgl::OfflineRegion> region; - mbgl::DefaultFileSource& fileSource; + std::shared_ptr<mbgl::DefaultFileSource> fileSource; }; } // namespace android diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp index 8eb1d02605..47a2781cb5 100644 --- a/platform/android/src/snapshotter/map_snapshotter.cpp +++ b/platform/android/src/snapshotter/map_snapshotter.cpp @@ -37,7 +37,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, } jFileSource = FileSource::getNativePeer(_env, _jFileSource); - auto& fileSource = mbgl::android::FileSource::getDefaultFileSource(_env, _jFileSource); auto size = mbgl::Size { static_cast<uint32_t>(width), static_cast<uint32_t>(height) }; optional<mbgl::CameraOptions> cameraOptions; @@ -56,11 +55,10 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, } else { style = std::make_pair(false, jni::Make<std::string>(_env, styleURL)); } - + showLogo = _showLogo; // Create the core snapshotter - snapshotter = std::make_unique<mbgl::MapSnapshotter>(&fileSource, - threadPool, + snapshotter = std::make_unique<mbgl::MapSnapshotter>(threadPool, style, size, pixelRatio, @@ -69,8 +67,8 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env, jni::Make<std::string>(_env, _programCacheDir), _localIdeographFontFamily ? jni::Make<std::string>(_env, _localIdeographFontFamily) : - optional<std::string>{}); - + optional<std::string>{}, + mbgl::android::FileSource::getSharedResourceOptions(_env, _jFileSource)); } MapSnapshotter::~MapSnapshotter() = default; diff --git a/platform/android/src/style/layers/symbol_layer.cpp b/platform/android/src/style/layers/symbol_layer.cpp index 61e4d59326..810848e9cb 100644 --- a/platform/android/src/style/layers/symbol_layer.cpp +++ b/platform/android/src/style/layers/symbol_layer.cpp @@ -176,6 +176,16 @@ namespace android { return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextJustify())); } + jni::Local<jni::Object<>> SymbolLayer::getTextRadialOffset(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextRadialOffset())); + } + + jni::Local<jni::Object<>> SymbolLayer::getTextVariableAnchor(jni::JNIEnv& env) { + using namespace mbgl::android::conversion; + return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextVariableAnchor())); + } + jni::Local<jni::Object<>> SymbolLayer::getTextAnchor(jni::JNIEnv& env) { using namespace mbgl::android::conversion; return std::move(*convert<jni::Local<jni::Object<>>>(env, toSymbolLayer(layer).getTextAnchor())); @@ -514,6 +524,8 @@ namespace android { METHOD(&SymbolLayer::getTextLineHeight, "nativeGetTextLineHeight"), METHOD(&SymbolLayer::getTextLetterSpacing, "nativeGetTextLetterSpacing"), METHOD(&SymbolLayer::getTextJustify, "nativeGetTextJustify"), + METHOD(&SymbolLayer::getTextRadialOffset, "nativeGetTextRadialOffset"), + METHOD(&SymbolLayer::getTextVariableAnchor, "nativeGetTextVariableAnchor"), METHOD(&SymbolLayer::getTextAnchor, "nativeGetTextAnchor"), METHOD(&SymbolLayer::getTextMaxAngle, "nativeGetTextMaxAngle"), METHOD(&SymbolLayer::getTextRotate, "nativeGetTextRotate"), diff --git a/platform/android/src/style/layers/symbol_layer.hpp b/platform/android/src/style/layers/symbol_layer.hpp index f52597ef6f..3b0f8ee5d1 100644 --- a/platform/android/src/style/layers/symbol_layer.hpp +++ b/platform/android/src/style/layers/symbol_layer.hpp @@ -80,6 +80,10 @@ public: jni::Local<jni::Object<jni::ObjectTag>> getTextJustify(jni::JNIEnv&); + jni::Local<jni::Object<jni::ObjectTag>> getTextRadialOffset(jni::JNIEnv&); + + jni::Local<jni::Object<jni::ObjectTag>> getTextVariableAnchor(jni::JNIEnv&); + jni::Local<jni::Object<jni::ObjectTag>> getTextAnchor(jni::JNIEnv&); jni::Local<jni::Object<jni::ObjectTag>> getTextMaxAngle(jni::JNIEnv&); diff --git a/platform/android/vendor/mapbox-events-android b/platform/android/vendor/mapbox-events-android -Subproject 1636d1ae9d5b0f0dd2367c8f32f1af958640b14 +Subproject 5bdf0d90292fb46cd8b1f795763d281b5ac83e0 diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index cf0f79f419..8df541d0f7 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -431,5 +431,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md index 5f5d9a22a8..b2e01b94db 100644 --- a/platform/darwin/docs/guides/Predicates and Expressions.md +++ b/platform/darwin/docs/guides/Predicates and Expressions.md @@ -546,6 +546,14 @@ operator in the Mapbox Style Specification. Concatenates and returns the array of `MGLAttributedExpression` objects, for use with the `MGLSymbolStyleLayer.text` property. +`MGLAttributedExpression.attributes` valid attributes. + + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array. + `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value. + `MGLFontColorAttribute` | An `NSExpression` evaluating to an `UIColor` (iOS) or `NSColor` (macOS). + This function corresponds to the [`format`](https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-types-format) operator in the Mapbox Style Specification. diff --git a/platform/darwin/filesource-files.json b/platform/darwin/filesource-files.json index 3ee96f9b95..b2e6fbc9b4 100644 --- a/platform/darwin/filesource-files.json +++ b/platform/darwin/filesource-files.json @@ -4,6 +4,7 @@ "platform/darwin/src/MGLLoggingConfiguration.m", "platform/darwin/src/MGLNetworkConfiguration.m", "platform/darwin/src/http_file_source.mm", + "platform/default/src/mbgl/storage/file_source.cpp", "platform/default/src/mbgl/storage/sqlite3.cpp" ], "public_headers": {}, diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index a8bdec7865..2eabd0a92b 100755 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -137,6 +137,8 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { } return '@"{1, 1}"'; } + case 'anchor': + return `@"{'top','bottom'}"`; default: throw new Error(`unknown array type for ${property.name}`); } @@ -185,6 +187,8 @@ global.mbglTestValue = function (property, layerType) { case 'offset': case 'translate': return '{ 1, 1 }'; + case 'anchor': + return '{ mbgl::style::SymbolAnchorType::Top, mbgl::style::SymbolAnchorType::Bottom }'; default: throw new Error(`unknown array type for ${property.name}`); } @@ -200,6 +204,13 @@ global.mbglExpressionTestValue = function (property, layerType) { return `"${_.last(_.keys(property.values))}"`; case 'color': return 'mbgl::Color(1, 0, 0, 1)'; + case 'array': + switch (arrayType(property)) { + case 'anchor': + return `{"top", "bottom"}`; + default: + break; + } default: return global.mbglTestValue(property, layerType); } @@ -341,6 +352,9 @@ global.propertyDoc = function (propertyName, property, layerType, kind) { if (property.type === 'enum') { doc += '* Any of the following constant string values:\n'; doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n'; + } else if (property.type === 'array' && property.value === 'enum') { + doc += '* Constant array, whose each element is any of the following constant string values:\n'; + doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n'; } doc += '* Predefined functions, including mathematical and string operators\n' + '* Conditional expressions\n' + @@ -415,6 +429,8 @@ global.describeType = function (property) { return '`CGVector`'; case 'position': return '`MGLSphericalPosition`'; + case 'anchor': + return '`MGLTextAnchor` array'; default: return 'array'; } @@ -539,11 +555,12 @@ global.propertyType = function (property) { case 'font': return 'NSArray<NSString *> *'; case 'padding': - return 'NSValue *'; case 'position': case 'offset': case 'translate': return 'NSValue *'; + case 'anchor': + return 'NSArray<NSValue *> *'; default: throw new Error(`unknown array type for ${property.name}`); } @@ -588,6 +605,8 @@ global.valueTransformerArguments = function (property) { case 'offset': case 'translate': return ['std::array<float, 2>', objCType]; + case 'anchor': + return ['std::vector<mbgl::style::SymbolAnchorType>', objCType, 'mbgl::style::SymbolAnchorType', 'MGLTextAnchor']; default: throw new Error(`unknown array type for ${property.name}`); } @@ -637,6 +656,8 @@ global.mbglType = function(property) { return 'std::array<float, 2>'; case 'position': return 'mbgl::style::Position'; + case 'anchor': + return 'std::vector<mbgl::style::SymbolAnchorType>'; default: throw new Error(`unknown array type for ${property.name}`); } diff --git a/platform/darwin/src/MGLAttributedExpression.h b/platform/darwin/src/MGLAttributedExpression.h index aa5d51c66e..ea298c7a44 100644 --- a/platform/darwin/src/MGLAttributedExpression.h +++ b/platform/darwin/src/MGLAttributedExpression.h @@ -2,14 +2,33 @@ NS_ASSUME_NONNULL_BEGIN -typedef NSString * MGLAttributedExpressionKey NS_EXTENSIBLE_STRING_ENUM; +/** Options for `MGLAttributedExpression.attributes`. */ +typedef NSString * MGLAttributedExpressionKey NS_TYPED_ENUM; +/** The font name string array expression used to format the text. */ FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontNamesAttribute; -FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontSizeAttribute; + +/** The font scale number expression relative to `MGLSymbolStyleLayer.textFontSize` used to format the text. */ +FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontScaleAttribute; + +/** The font color expression used to format the text. */ +FOUNDATION_EXTERN MGL_EXPORT MGLAttributedExpressionKey const MGLFontColorAttribute; /** An `MGLAttributedExpression` object associates text formatting attibutes (such as font size or font names) to an `NSExpression`. + + ### Example + ```swift + let redColor = UIColor.red + let expression = NSExpression(forConstantValue: "Foo") + let attributes: [MGLAttributedExpressionKey: NSExpression] = [.fontNamesAttribute : NSExpression(forConstantValue: ["DIN Offc Pro Italic", + "Arial Unicode MS Regular"]), + .fontScaleAttribute: NSExpression(forConstantValue: 1.2), + .fontColorAttribute: NSExpression(forConstantValue: redColor)] + let attributedExpression = MGLAttributedExpression(expression, attributes:attributes) + ``` + */ MGL_EXPORT @interface MGLAttributedExpression : NSObject @@ -19,10 +38,29 @@ MGL_EXPORT */ @property (strong, nonatomic) NSExpression *expression; +#if TARGET_OS_IPHONE +/** + The formatting attributes dictionary. + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array. + `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value. + `MGLFontColorAttribute` | An `NSExpression` evaluating to an `UIColor`. + + */ +@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, NSExpression *> *attributes; +#else /** - The formatting attributes. + The formatting attributes dictionary. + Key | Value Type + --- | --- + `MGLFontNamesAttribute` | An `NSExpression` evaluating to an `NSString` array. + `MGLFontScaleAttribute` | An `NSExpression` evaluating to an `NSNumber` value. + `MGLFontColorAttribute` | An `NSExpression` evaluating to an `NSColor` on macos. */ -@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, id> *attributes; +@property (strong, nonatomic, readonly) NSDictionary<MGLAttributedExpressionKey, NSExpression *> *attributes; +#endif + /** Returns an `MGLAttributedExpression` object initialized with an expression and no attribute information. @@ -32,12 +70,17 @@ MGL_EXPORT /** Returns an `MGLAttributedExpression` object initialized with an expression and text format attributes. */ -- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nullable NSDictionary <MGLAttributedExpressionKey, id> *)attrs; +- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary <MGLAttributedExpressionKey, NSExpression *> *)attrs; /** Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes for font names and font size. */ -+ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString*> *)fontNames fontSize:(nullable NSNumber *)fontSize; ++ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString*> *)fontNames fontScale:(nullable NSNumber *)fontScale; + +/** + Creates an `MGLAttributedExpression` object initialized with an expression and the format attributes dictionary. + */ ++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary <MGLAttributedExpressionKey, NSExpression *> *)attrs; @end diff --git a/platform/darwin/src/MGLAttributedExpression.m b/platform/darwin/src/MGLAttributedExpression.m index 715f74e42f..a34480a957 100644 --- a/platform/darwin/src/MGLAttributedExpression.m +++ b/platform/darwin/src/MGLAttributedExpression.m @@ -2,33 +2,42 @@ #import "MGLLoggingConfiguration_Private.h" const MGLAttributedExpressionKey MGLFontNamesAttribute = @"text-font"; -const MGLAttributedExpressionKey MGLFontSizeAttribute = @"font-scale"; +const MGLAttributedExpressionKey MGLFontScaleAttribute = @"font-scale"; +const MGLAttributedExpressionKey MGLFontColorAttribute = @"text-color"; @implementation MGLAttributedExpression - (instancetype)initWithExpression:(NSExpression *)expression { - self = [self initWithExpression:expression attributes:nil]; + self = [self initWithExpression:expression attributes:@{}]; return self; } -+ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString *> *)fontNames fontSize:(nullable NSNumber *)fontSize { ++ (instancetype)attributedExpression:(NSExpression *)expression fontNames:(nullable NSArray<NSString *> *)fontNames fontScale:(nullable NSNumber *)fontScale { MGLAttributedExpression *attributedExpression; NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; if (fontNames && fontNames.count > 0) { - attrs[MGLFontNamesAttribute] = fontNames; + attrs[MGLFontNamesAttribute] = [NSExpression expressionForConstantValue:fontNames]; } - if (fontSize) { - attrs[MGLFontSizeAttribute] = fontSize; + if (fontScale) { + attrs[MGLFontScaleAttribute] = [NSExpression expressionForConstantValue:fontScale]; } attributedExpression = [[self alloc] initWithExpression:expression attributes:attrs]; return attributedExpression; } -- (instancetype)initWithExpression:(NSExpression *)expression attributes:(NSDictionary<MGLAttributedExpressionKey,id> *)attrs { ++ (instancetype)attributedExpression:(NSExpression *)expression attributes:(nonnull NSDictionary<MGLAttributedExpressionKey, NSExpression *> *)attrs { + MGLAttributedExpression *attributedExpression; + + attributedExpression = [[self alloc] initWithExpression:expression attributes:attrs]; + + return attributedExpression; +} + +- (instancetype)initWithExpression:(NSExpression *)expression attributes:(nonnull NSDictionary<MGLAttributedExpressionKey, NSExpression *> *)attrs { if (self = [super init]) { MGLLogInfo(@"Starting %@ initialization.", NSStringFromClass([self class])); diff --git a/platform/darwin/src/MGLLoggingConfiguration.h b/platform/darwin/src/MGLLoggingConfiguration.h index 6782dc60a7..d79336df4c 100644 --- a/platform/darwin/src/MGLLoggingConfiguration.h +++ b/platform/darwin/src/MGLLoggingConfiguration.h @@ -4,7 +4,7 @@ #ifndef MGL_LOGGING_DISABLED #ifndef MGL_LOGGING_ENABLE_DEBUG - #ifdef DEBUG + #ifndef NDEBUG #define MGL_LOGGING_ENABLE_DEBUG 1 #endif #endif diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 3918008b78..171f24e4d0 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -3,8 +3,10 @@ #import <mbgl/actor/actor.hpp> #import <mbgl/actor/scheduler.hpp> #import <mbgl/util/geo.hpp> +#import <mbgl/map/map_options.hpp> #import <mbgl/map/map_snapshotter.hpp> #import <mbgl/map/camera.hpp> +#import <mbgl/storage/resource_options.hpp> #import <mbgl/storage/default_file_source.hpp> #import <mbgl/util/default_thread_pool.hpp> #import <mbgl/util/string.hpp> @@ -587,7 +589,9 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; _cancelled = NO; _options = options; - mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + + auto mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + _mbglThreadPool = mbgl::sharedThreadPool(); std::string styleURL = std::string([options.styleURL.absoluteString UTF8String]); @@ -619,9 +623,14 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; // App-global configuration MGLRendererConfiguration* config = [MGLRendererConfiguration currentConfiguration]; - + + mbgl::ResourceOptions resourceOptions; + resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath]) + .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String); + // Create the snapshotter - _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(mbglFileSource, _mbglThreadPool, style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName); + _mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>( + _mbglThreadPool, style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName, resourceOptions); } @end diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm index a8f807374c..0f2e8180fa 100644 --- a/platform/darwin/src/MGLOfflinePack.mm +++ b/platform/darwin/src/MGLOfflinePack.mm @@ -10,6 +10,7 @@ #import "NSValue+MGLAdditions.h" +#include <mbgl/map/map_options.hpp> #include <mbgl/storage/default_file_source.hpp> const MGLExceptionName MGLInvalidOfflinePackException = @"MGLInvalidOfflinePackException"; @@ -58,6 +59,7 @@ private: @implementation MGLOfflinePack { BOOL _isSuspending; + std::shared_ptr<mbgl::DefaultFileSource> _mbglFileSource; } - (instancetype)init { @@ -74,8 +76,8 @@ private: _mbglOfflineRegion = region; _state = MGLOfflinePackStateUnknown; - mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; - mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique<MBGLOfflineRegionObserver>(self)); + _mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; + _mbglFileSource->setOfflineRegionObserver(*_mbglOfflineRegion, std::make_unique<MBGLOfflineRegionObserver>(self)); } return self; } @@ -115,8 +117,7 @@ private: self.state = MGLOfflinePackStateActive; - mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; - mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active); + _mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Active); } - (void)suspend { @@ -128,8 +129,7 @@ private: _isSuspending = YES; } - mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; - mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive); + _mbglFileSource->setOfflineRegionDownloadState(*_mbglOfflineRegion, mbgl::OfflineRegionDownloadState::Inactive); } - (void)invalidate { @@ -137,8 +137,7 @@ private: MGLAssert(_state != MGLOfflinePackStateInvalid, @"Cannot invalidate an already invalid offline pack."); self.state = MGLOfflinePackStateInvalid; - mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; - mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr); + _mbglFileSource->setOfflineRegionObserver(*self.mbglOfflineRegion, nullptr); self.mbglOfflineRegion = nil; } @@ -164,10 +163,8 @@ private: MGLLogInfo(@"Requesting pack progress."); MGLAssertOfflinePackIsValid(); - mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; - __weak MGLOfflinePack *weakSelf = self; - mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) { + _mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](mbgl::expected<mbgl::OfflineRegionStatus, std::exception_ptr> status) { if (status) { mbgl::OfflineRegionStatus checkedStatus = *status; dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/platform/darwin/src/MGLOfflinePack_Private.h b/platform/darwin/src/MGLOfflinePack_Private.h index 8a63152dca..ea3fb2da99 100644 --- a/platform/darwin/src/MGLOfflinePack_Private.h +++ b/platform/darwin/src/MGLOfflinePack_Private.h @@ -1,6 +1,6 @@ #import "MGLOfflinePack.h" -#include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/offline.hpp> NS_ASSUME_NONNULL_BEGIN diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index 4613b402fd..6effd8c3ce 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -10,7 +10,6 @@ #import "NSBundle+MGLAdditions.h" #import "NSValue+MGLAdditions.h" #import "NSDate+MGLAdditions.h" -#import "NSData+MGLAdditions.h" #import "MGLLoggingConfiguration_Private.h" #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR @@ -20,6 +19,8 @@ #include <mbgl/actor/actor.hpp> #include <mbgl/actor/scheduler.hpp> +#include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/resource_transform.hpp> #include <mbgl/util/chrono.hpp> #include <mbgl/util/run_loop.hpp> @@ -44,7 +45,8 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio @interface MGLOfflineStorage () @property (nonatomic, strong, readwrite) NSMutableArray<MGLOfflinePack *> *packs; -@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; +@property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource; +@property (nonatomic) std::string mbglCachePath; @property (nonatomic, getter=isPaused) BOOL paused; @end @@ -223,7 +225,11 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio [[NSFileManager defaultManager] moveItemAtPath:subdirectorylessCacheURL.path toPath:cachePath error:NULL]; } - _mbglFileSource = new mbgl::DefaultFileSource(cachePath.UTF8String, [NSBundle mainBundle].resourceURL.path.UTF8String); + _mbglCachePath = cachePath.UTF8String; + mbgl::ResourceOptions options; + options.withCachePath(_mbglCachePath) + .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String); + _mbglFileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(options)); // Observe for changes to the API base URL (and find out the current one). [[MGLAccountManager sharedManager] addObserver:self @@ -250,9 +256,6 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio for (MGLOfflinePack *pack in self.packs) { [pack invalidate]; } - - delete _mbglFileSource; - _mbglFileSource = nullptr; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context { @@ -260,14 +263,14 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) { NSString *accessToken = change[NSKeyValueChangeNewKey]; if (![accessToken isKindOfClass:[NSNull class]]) { - self.mbglFileSource->setAccessToken(accessToken.UTF8String); + _mbglFileSource->setAccessToken(accessToken.UTF8String); } } else if ([keyPath isEqualToString:@"apiBaseURL"] && object == [MGLAccountManager sharedManager]) { NSURL *apiBaseURL = change[NSKeyValueChangeNewKey]; if ([apiBaseURL isKindOfClass:[NSNull class]]) { - self.mbglFileSource->setAPIBaseURL(mbgl::util::API_BASE_URL); + _mbglFileSource->setAPIBaseURL(mbgl::util::API_BASE_URL); } else { - self.mbglFileSource->setAPIBaseURL(apiBaseURL.absoluteString.UTF8String); + _mbglFileSource->setAPIBaseURL(apiBaseURL.absoluteString.UTF8String); } } else { [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; @@ -333,7 +336,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio } - (void)_addContentsOfFile:(NSString *)filePath withCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> * _Nullable packs, NSError * _Nullable error))completion { - self.mbglFileSource->mergeOfflineRegions(std::string(static_cast<const char *>([filePath UTF8String])), [&, completion, filePath](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) { + _mbglFileSource->mergeOfflineRegions(std::string(static_cast<const char *>([filePath UTF8String])), [&, completion, filePath](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) { NSError *error; NSMutableArray *packs; if (!result) { @@ -394,7 +397,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio const mbgl::OfflineRegionDefinition regionDefinition = [(id <MGLOfflineRegion_Private>)region offlineRegionDefinition]; mbgl::OfflineRegionMetadata metadata(context.length); [context getBytes:&metadata[0] length:metadata.size()]; - self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> mbglOfflineRegion) { + _mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected<mbgl::OfflineRegion, std::exception_ptr> mbglOfflineRegion) { NSError *error; if (!mbglOfflineRegion) { NSString *errorDescription = @(mbgl::util::toString(mbglOfflineRegion.error()).c_str()); @@ -429,7 +432,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio return; } - self.mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) { + _mbglFileSource->deleteOfflineRegion(std::move(*mbglOfflineRegion), [&, completion](std::exception_ptr exception) { NSError *error; if (exception) { error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ @@ -455,7 +458,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio } - (void)getPacksWithCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> *packs, NSError * _Nullable error))completion { - self.mbglFileSource->listOfflineRegions([&, completion](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) { + _mbglFileSource->listOfflineRegions([&, completion](mbgl::expected<mbgl::OfflineRegions, std::exception_ptr> result) { NSError *error; NSMutableArray *packs; if (!result) { diff --git a/platform/darwin/src/MGLOfflineStorage_Private.h b/platform/darwin/src/MGLOfflineStorage_Private.h index 7c7b80dc46..5ac64ea995 100644 --- a/platform/darwin/src/MGLOfflineStorage_Private.h +++ b/platform/darwin/src/MGLOfflineStorage_Private.h @@ -4,6 +4,8 @@ #include <mbgl/storage/default_file_source.hpp> +#include <memory> + NS_ASSUME_NONNULL_BEGIN @interface MGLOfflineStorage (Private) @@ -11,7 +13,12 @@ NS_ASSUME_NONNULL_BEGIN /** The shared file source object owned by the shared offline storage object. */ -@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource; +@property (nonatomic) std::shared_ptr<mbgl::DefaultFileSource> mbglFileSource; + +/** + The shared offline cache path. + */ +@property (nonatomic) std::string mbglCachePath; @end diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h index a2ad4d6cdc..ef7122ec51 100644 --- a/platform/darwin/src/MGLRendererConfiguration.h +++ b/platform/darwin/src/MGLRendererConfiguration.h @@ -1,7 +1,8 @@ #import "MGLFoundation.h" #import <Foundation/Foundation.h> -#import <mbgl/storage/default_file_source.hpp> -#import <mbgl/renderer/mode.hpp> + +#include <mbgl/renderer/mode.hpp> +#include <mbgl/util/optional.hpp> NS_ASSUME_NONNULL_BEGIN @@ -15,9 +16,6 @@ MGL_EXPORT /** Returns an instance of the current renderer configuration. */ @property (class, nonatomic, readonly) MGLRendererConfiguration *currentConfiguration; -/** The file source to use. Defaults to `mbgl::DefaultFileSource` */ -@property (nonatomic, readonly) mbgl::DefaultFileSource *fileSource; - /** The GL context mode to use. Defaults to `mbgl::GLContextMode::Unique` */ @property (nonatomic, readonly) mbgl::GLContextMode contextMode; diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm index 7a2f95cfda..78201987fe 100644 --- a/platform/darwin/src/MGLRendererConfiguration.mm +++ b/platform/darwin/src/MGLRendererConfiguration.mm @@ -57,10 +57,6 @@ static NSString * const MGLCollisionBehaviorPre4_0Key = @"MGLCollisionBehaviorPr return self; } -- (mbgl::DefaultFileSource *)fileSource { - return [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; -} - - (mbgl::GLContextMode)contextMode { return mbgl::GLContextMode::Unique; } diff --git a/platform/darwin/src/MGLRendererFrontend.h b/platform/darwin/src/MGLRendererFrontend.h index 2df67ca4e4..c0e03351c6 100644 --- a/platform/darwin/src/MGLRendererFrontend.h +++ b/platform/darwin/src/MGLRendererFrontend.h @@ -49,7 +49,12 @@ public: mbgl::BackendScope guard { mbglBackend, mbgl::BackendScope::ScopeType::Implicit }; - renderer->render(*updateParameters); + // onStyleImageMissing might be called during a render. The user implemented method + // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`. + // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is + // still using them. + auto updateParameters_ = updateParameters; + renderer->render(*updateParameters_); } mbgl::Renderer* getRenderer() { diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 84d7ccccec..fee34b4b71 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -307,10 +307,8 @@ private: // Private utilities for converting from mbgl to mgl values // 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)]; + static NSString *toMGLRawStyleValue(const MBGLEnum &value) { + return @(mbgl::Enum<MBGLEnum>::toString(value)); } /// Converts all types of mbgl property values into an equivalent NSExpression. @@ -320,15 +318,6 @@ private: // Private utilities for converting from mbgl to mgl values return nil; } - /** - 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> NSExpression *operator()(const MBGLType &value) const { id constantValue = toMGLRawStyleValue(value); if ([constantValue isKindOfClass:[NSArray class]]) { @@ -337,15 +326,6 @@ private: // Private utilities for converting from mbgl to mgl values return [NSExpression expressionForConstantValue:constantValue]; } - 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> - NSExpression *operator()(const MBGLEnum &value) const { - NSString *constantValue = @(mbgl::Enum<MBGLEnum>::toString(value)); - return [NSExpression expressionForConstantValue:constantValue]; - } - NSExpression *operator()(const mbgl::style::PropertyExpression<MBGLType> &mbglValue) const { return [NSExpression expressionWithMGLJSONObject:MGLJSONObjectFromMBGLExpression(mbglValue.getExpression())]; } diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h index ee8afb1fb2..cf2c1466e7 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.h +++ b/platform/darwin/src/MGLSymbolStyleLayer.h @@ -223,6 +223,10 @@ typedef NS_ENUM(NSUInteger, MGLTextAnchor) { */ typedef NS_ENUM(NSUInteger, MGLTextJustification) { /** + The text is aligned towards the anchor position. + */ + MGLTextJustificationAuto, + /** The text is aligned to the left. */ MGLTextJustificationLeft, @@ -1279,6 +1283,7 @@ MGL_EXPORT * Constant `MGLTextJustification` values * Any of the following constant string values: + * `auto`: The text is aligned towards the anchor position. * `left`: The text is aligned to the left. * `center`: The text is centered. * `right`: The text is aligned to the right. @@ -1349,8 +1354,8 @@ MGL_EXPORT `NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0 ems downward. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `text` is non-`nil`. Otherwise, - it is ignored. + This property is only applied to the style if `text` is non-`nil`, and + `textRadialOffset` is set to `nil`. Otherwise, it is ignored. You can set this property to an expression containing any of the following: @@ -1372,8 +1377,8 @@ MGL_EXPORT `NSValue` object containing a `CGVector` struct set to 0 ems rightward and 0 ems upward. Set this property to `nil` to reset it to the default value. - This property is only applied to the style if `text` is non-`nil`. Otherwise, - it is ignored. + This property is only applied to the style if `text` is non-`nil`, and + `textRadialOffset` is set to `nil`. Otherwise, it is ignored. You can set this property to an expression containing any of the following: @@ -1464,6 +1469,27 @@ MGL_EXPORT @property (nonatomic, null_resettable) NSExpression *textPitchAlignment; /** + Radial offset of text, in the direction of the symbol's anchor. Useful in + combination with `textVariableAnchor`, which doesn't support the + two-dimensional `textOffset`. + + This property is measured in ems. + + This property is only applied to the style if `textOffset` is set to `nil`. + Otherwise, it is ignored. + + You can set this property to an expression containing any of the following: + + * Constant numeric values + * Predefined functions, including mathematical and string operators + * Conditional expressions + * Variable assignments and references to assigned variables + * Interpolation and step functions applied to the `$zoomLevel` variable and/or + feature attributes + */ +@property (nonatomic, null_resettable) NSExpression *textRadialOffset; + +/** Rotates the text clockwise. This property is measured in degrees. @@ -1549,6 +1575,47 @@ MGL_EXPORT */ @property (nonatomic, null_resettable) NSExpression *textTransform; +/** + To increase the chance of placing high-priority labels on the map, you can + provide an array of `textAnchor` locations: the render will attempt to place + the label at each location, in order, before moving onto the next label. Use + `textJustify: auto` to choose justification based on anchor position. To apply + an offset, use the `textRadialOffset` instead of the two-dimensional + `textOffset`. + + This property is only applied to the style if `textAnchor` is set to `nil`, and + `textOffset` is set to `nil`, and `symbolPlacement` is set to an expression + that evaluates to or `MGLSymbolPlacementPoint`. Otherwise, it is ignored. + + You can set this property to an expression containing any of the following: + + * Constant `MGLTextAnchor` array values + * Constant array, whose each element is any of the following constant string + values: + * `center`: The center of the text is placed closest to the anchor. + * `left`: The left side of the text is placed closest to the anchor. + * `right`: The right side of the text is placed closest to the anchor. + * `top`: The top of the text is placed closest to the anchor. + * `bottom`: The bottom of the text is placed closest to the anchor. + * `top-left`: The top left corner of the text is placed closest to the + anchor. + * `top-right`: The top right corner of the text is placed closest to the + anchor. + * `bottom-left`: The bottom left corner of the text is placed closest to the + anchor. + * `bottom-right`: The bottom right corner of the text is placed closest to + the anchor. + * Predefined functions, including mathematical and string operators + * Conditional expressions + * Variable assignments and references to assigned variables + * Step functions applied to the `$zoomLevel` variable + + This property does not support applying interpolation functions to the + `$zoomLevel` variable or applying interpolation or step functions to feature + attributes. + */ +@property (nonatomic, null_resettable) NSExpression *textVariableAnchor; + #pragma mark - Accessing the Paint Attributes #if TARGET_OS_IPHONE diff --git a/platform/darwin/src/MGLSymbolStyleLayer.mm b/platform/darwin/src/MGLSymbolStyleLayer.mm index 60fc4d6881..6d91bbe87f 100644 --- a/platform/darwin/src/MGLSymbolStyleLayer.mm +++ b/platform/darwin/src/MGLSymbolStyleLayer.mm @@ -71,6 +71,7 @@ namespace mbgl { }); MBGL_DEFINE_ENUM(MGLTextJustification, { + { MGLTextJustificationAuto, "auto" }, { MGLTextJustificationLeft, "left" }, { MGLTextJustificationCenter, "center" }, { MGLTextJustificationRight, "right" }, @@ -906,6 +907,24 @@ namespace mbgl { return MGLStyleValueTransformer<mbgl::style::AlignmentType, NSValue *, mbgl::style::AlignmentType, MGLTextPitchAlignment>().toExpression(propertyValue); } +- (void)setTextRadialOffset:(NSExpression *)textRadialOffset { + MGLAssertStyleLayerIsValid(); + MGLLogDebug(@"Setting textRadialOffset: %@", textRadialOffset); + + auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toPropertyValue<mbgl::style::PropertyValue<float>>(textRadialOffset, true); + self.rawLayer->setTextRadialOffset(mbglValue); +} + +- (NSExpression *)textRadialOffset { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getTextRadialOffset(); + if (propertyValue.isUndefined()) { + propertyValue = self.rawLayer->getDefaultTextRadialOffset(); + } + return MGLStyleValueTransformer<float, NSNumber *>().toExpression(propertyValue); +} + - (void)setTextRotation:(NSExpression *)textRotation { MGLAssertStyleLayerIsValid(); MGLLogDebug(@"Setting textRotation: %@", textRotation); @@ -967,6 +986,24 @@ namespace mbgl { return MGLStyleValueTransformer<mbgl::style::TextTransformType, NSValue *, mbgl::style::TextTransformType, MGLTextTransform>().toExpression(propertyValue); } +- (void)setTextVariableAnchor:(NSExpression *)textVariableAnchor { + MGLAssertStyleLayerIsValid(); + MGLLogDebug(@"Setting textVariableAnchor: %@", textVariableAnchor); + + auto mbglValue = MGLStyleValueTransformer<std::vector<mbgl::style::SymbolAnchorType>, NSArray<NSValue *> *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toPropertyValue<mbgl::style::PropertyValue<std::vector<mbgl::style::SymbolAnchorType>>>(textVariableAnchor, false); + self.rawLayer->setTextVariableAnchor(mbglValue); +} + +- (NSExpression *)textVariableAnchor { + MGLAssertStyleLayerIsValid(); + + auto propertyValue = self.rawLayer->getTextVariableAnchor(); + if (propertyValue.isUndefined()) { + propertyValue = self.rawLayer->getDefaultTextVariableAnchor(); + } + return MGLStyleValueTransformer<std::vector<mbgl::style::SymbolAnchorType>, NSArray<NSValue *> *, mbgl::style::SymbolAnchorType, MGLTextAnchor>().toExpression(propertyValue); +} + #pragma mark - Accessing the Paint Attributes - (void)setIconColor:(NSExpression *)iconColor { diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m index d472e40b1f..da70a95373 100644 --- a/platform/darwin/src/NSBundle+MGLAdditions.m +++ b/platform/darwin/src/NSBundle+MGLAdditions.m @@ -35,10 +35,15 @@ const MGLExceptionName MGLBundleNotFoundException = @"MGLBundleNotFoundException + (nullable NSString *)mgl_applicationBundleIdentifier { NSString *bundleIdentifier = [NSBundle mainBundle].bundleIdentifier; + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && (__IPHONE_OS_VERSION_MAX_ALLOWED < 120200)) || \ + (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101404)) + // Before SDK 12.2 (bundled with Xcode 10.2): There’s no main bundle identifier when running in a unit test bundle. + // 12.2 and after: the above bundle identifier is: com.apple.dt.xctest.tool if (!bundleIdentifier) { - // There’s no main bundle identifier when running in a unit test bundle. bundleIdentifier = [NSBundle bundleForClass:[MGLAccountManager class]].bundleIdentifier; } +#endif return bundleIdentifier; } diff --git a/platform/darwin/src/NSData+MGLAdditions.h b/platform/darwin/src/NSData+MGLAdditions.h deleted file mode 100644 index 38af7961b6..0000000000 --- a/platform/darwin/src/NSData+MGLAdditions.h +++ /dev/null @@ -1,13 +0,0 @@ -#import <Foundation/Foundation.h> - -NS_ASSUME_NONNULL_BEGIN - -@interface NSData (MGLAdditions) - -- (NSData *)mgl_compressedData; - -- (NSData *)mgl_decompressedData; - -@end - -NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/NSData+MGLAdditions.mm b/platform/darwin/src/NSData+MGLAdditions.mm deleted file mode 100644 index 97c3bb4a26..0000000000 --- a/platform/darwin/src/NSData+MGLAdditions.mm +++ /dev/null @@ -1,23 +0,0 @@ -#import "NSData+MGLAdditions.h" - -#include <mbgl/util/compression.hpp> - -@implementation NSData (MGLAdditions) - -- (NSData *)mgl_compressedData -{ - 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()]; -} - -- (NSData *)mgl_decompressedData -{ - 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()]; -} - -@end diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index c4e2908888..4b1fdb818e 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -1,3 +1,4 @@ +#import "MGLFoundation_Private.h" #import "NSExpression+MGLPrivateAdditions.h" #import "MGLTypes.h" @@ -878,9 +879,12 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { NSExpression *expression = [NSExpression expressionWithMGLJSONObject:argumentObjects[index]]; NSMutableDictionary *attrs = [NSMutableDictionary dictionary]; if ((index + 1) < argumentObjects.count) { - attrs = argumentObjects[index + 1]; + attrs = [NSMutableDictionary dictionaryWithDictionary:argumentObjects[index + 1]]; } + for (NSString *key in attrs.allKeys) { + attrs[key] = [NSExpression expressionWithMGLJSONObject:attrs[key]]; + } MGLAttributedExpression *attributedExpression = [[MGLAttributedExpression alloc] initWithExpression:expression attributes:attrs]; [attributedExpressions addObject:[NSExpression expressionForConstantValue:attributedExpression]]; @@ -1001,19 +1005,17 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { if ([constantValue isKindOfClass:[MGLAttributedExpression class]]) { MGLAttributedExpression *attributedExpression = (MGLAttributedExpression *)constantValue; id jsonObject = attributedExpression.expression.mgl_jsonExpressionObject; - NSMutableArray *attributes = [NSMutableArray array]; - if ([jsonObject isKindOfClass:[NSArray class]]) { - [attributes addObjectsFromArray:jsonObject]; - } else { - [attributes addObject:jsonObject]; - } + NSMutableDictionary<MGLAttributedExpressionKey, NSExpression *> *attributedDictionary = [NSMutableDictionary dictionary]; + if (attributedExpression.attributes) { - [attributes addObject:attributedExpression.attributes]; - } else { - [attributes addObject:@{}]; - } - - return attributes; + attributedDictionary = [NSMutableDictionary dictionaryWithDictionary:attributedExpression.attributes]; + + for (NSString *key in attributedExpression.attributes.allKeys) { + attributedDictionary[key] = attributedExpression.attributes[key].mgl_jsonExpressionObject; + } + + } + return @[jsonObject, attributedDictionary]; } return self.constantValue; } @@ -1215,27 +1217,10 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { } case NSConditionalExpressionType: { - NSMutableArray *arguments = [NSMutableArray arrayWithObjects:self.predicate.mgl_jsonExpressionObject, nil]; - - if (self.trueExpression.expressionType == NSConditionalExpressionType) { - // Fold nested conditionals into a single case expression. - NSArray *trueArguments = self.trueExpression.mgl_jsonExpressionObject; - trueArguments = [trueArguments subarrayWithRange:NSMakeRange(1, trueArguments.count - 1)]; - [arguments addObjectsFromArray:trueArguments]; - } else { - [arguments addObject:self.trueExpression.mgl_jsonExpressionObject]; - } - - if (self.falseExpression.expressionType == NSConditionalExpressionType) { - // Fold nested conditionals into a single case expression. - NSArray *falseArguments = self.falseExpression.mgl_jsonExpressionObject; - falseArguments = [falseArguments subarrayWithRange:NSMakeRange(1, falseArguments.count - 1)]; - [arguments addObjectsFromArray:falseArguments]; - } else { - [arguments addObject:self.falseExpression.mgl_jsonExpressionObject]; - } + NSMutableArray *arguments = [NSMutableArray arrayWithObjects:@"case", self.predicate.mgl_jsonExpressionObject, nil]; + [arguments addObject:self.trueExpression.mgl_jsonExpressionObject]; + [arguments addObject:self.falseExpression.mgl_jsonExpressionObject]; - [arguments insertObject:@"case" atIndex:0]; return arguments; } diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m index 48779f3407..b6f053a8af 100644 --- a/platform/darwin/test/MGLAttributionInfoTests.m +++ b/platform/darwin/test/MGLAttributionInfoTests.m @@ -55,10 +55,21 @@ XCTAssertEqualObjects(infos[3].URL, [NSURL URLWithString:@"https://apps.mapbox.com/feedback/"]); XCTAssertTrue(infos[3].feedbackLink); NSURL *styleURL = [MGLStyle satelliteStreetsStyleURLWithVersion:99]; + +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 120200) || \ + (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101404) + NSString *bundleId = @"com.apple.dt.xctest.tool"; +#else + NSString *bundleId = @"com.mapbox.Mapbox"; +#endif + + NSString *urlString = [NSString stringWithFormat:@"https://apps.mapbox.com/feedback/?referrer=%@#/77.63680/12.98108/14.00/0.0/0", bundleId]; XCTAssertEqualObjects([infos[3] feedbackURLAtCenterCoordinate:mapbox zoomLevel:14], - [NSURL URLWithString:@"https://apps.mapbox.com/feedback/?referrer=com.mapbox.Mapbox#/77.63680/12.98108/14.00/0.0/0"]); + [NSURL URLWithString:urlString]); + + urlString = [NSString stringWithFormat:@"https://apps.mapbox.com/feedback/?referrer=%@&owner=mapbox&id=satellite-streets-v99&access_token=pk.feedcafedeadbeefbadebede&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13", bundleId]; XCTAssertEqualObjects([infos[3] feedbackURLForStyleURL:styleURL atCenterCoordinate:mapbox zoomLevel:3.14159 direction:90.9 pitch:12.5], - [NSURL URLWithString:@"https://apps.mapbox.com/feedback/?referrer=com.mapbox.Mapbox&owner=mapbox&id=satellite-streets-v99&access_token=pk.feedcafedeadbeefbadebede&map_sdk_version=1.0.0#/77.63680/12.98108/3.14/90.9/13"]); + [NSURL URLWithString:urlString]); } - (void)testStyle { diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 91fb02dfd2..2a64fbc601 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -542,6 +542,24 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { } } + func testMGLAttributedExpression() { + //#-example-code + #if os(macOS) + let redColor = NSColor.red + #else + let redColor = UIColor.red + #endif + let expression = NSExpression(forConstantValue: "Foo") + let attributes: [MGLAttributedExpressionKey: NSExpression] = [.fontNamesAttribute : NSExpression(forConstantValue: ["DIN Offc Pro Italic", + "Arial Unicode MS Regular"]), + .fontScaleAttribute: NSExpression(forConstantValue: 1.2), + .fontColorAttribute: NSExpression(forConstantValue: redColor)] + let attributedExpression = MGLAttributedExpression(expression, attributes:attributes) + //#-end-example-code + + XCTAssertNotNil(attributedExpression) + } + // For testMGLMapView(). func myCustomFunction() {} } diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index 8b8a79f184..68806e38f6 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -846,12 +846,9 @@ using namespace std::string_literals; } { NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"]; - NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO]; + NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"case", @[@"==", @1, @2], @YES, @NO]]; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO); - expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)", - MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]), - MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])]; XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); } { @@ -995,16 +992,16 @@ using namespace std::string_literals; { MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"] fontNames:nil - fontSize:@(1.2)]; + fontScale:@(1.2)]; MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"] fontNames:nil - fontSize:@(1.0)]; + fontScale:@(1.0)]; MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"] fontNames:nil - fontSize:@(0.8)]; + fontScale:@(0.8)]; MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\r"] fontNames:@[] - fontSize:nil]; + fontScale:nil]; NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@, %@, %@, %@)", MGLConstantExpression(attribute1), MGLConstantExpression(attribute4), @@ -1017,16 +1014,16 @@ using namespace std::string_literals; { MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"] fontNames:nil - fontSize:@(1.2)]; + fontScale:@(1.2)]; MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"] fontNames:nil - fontSize:@(1.0)]; + fontScale:@(1.0)]; MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"] fontNames:nil - fontSize:@(0.8)]; + fontScale:@(0.8)]; MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\n"] fontNames:@[] - fontSize:nil]; + fontScale:nil]; NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@, %@, %@, %@)", MGLConstantExpression(attribute1), MGLConstantExpression(attribute4), @@ -1039,7 +1036,7 @@ using namespace std::string_literals; { MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"] fontNames:nil - fontSize:@(1.2)]; + fontScale:@(1.2)]; NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; NSExpression *compatibilityExpression = [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[MGLConstantExpression(attribute1)]]; @@ -1050,18 +1047,79 @@ using namespace std::string_literals; XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); } { + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)), + MGLFontColorAttribute: MGLConstantExpression(@"yellow") }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSExpression *compatibilityExpression = [NSExpression expressionForFunction:@"mgl_attributed:" arguments:@[MGLConstantExpression(attribute1)]]; + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" } ]; + XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, expression.mgl_jsonExpressionObject); + XCTAssertEqualObjects(compatibilityExpression, expression); + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"]] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @"foo", @{ } ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]]; + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)), + MGLFontColorAttribute: MGLConstantExpression(@"yellow"), + MGLFontNamesAttribute: fontNames + }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @"yellow" , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + NSExpression *exp = [NSExpression expressionWithMGLJSONObject:jsonExpression]; + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]]; + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionForConstantValue:@"foo"] + attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)), + MGLFontColorAttribute: MGLConstantExpression([MGLColor redColor]), + MGLFontNamesAttribute: fontNames + }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @"foo", @{ @"font-scale": @1.2, @"text-color": @[@"rgb", @255, @0, @0] , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { + NSExpression *fontNames = [NSExpression expressionForAggregate:@[ MGLConstantExpression(@"DIN Offc Pro Bold"), MGLConstantExpression(@"Arial Unicode MS Bold") ]]; + MGLAttributedExpression *attribute1 = [[MGLAttributedExpression alloc] initWithExpression:[NSExpression expressionWithFormat:@"CAST(x, 'NSString')"] + attributes:@{ MGLFontScaleAttribute: MGLConstantExpression(@(1.2)), + MGLFontColorAttribute: MGLConstantExpression([MGLColor redColor]), + MGLFontNamesAttribute: fontNames + }] ; + NSExpression *expression = [NSExpression expressionWithFormat:@"mgl_attributed:(%@)", MGLConstantExpression(attribute1)]; + + NSArray *jsonExpression = @[ @"format", @[@"to-string", @[@"get", @"x"]], @{ @"font-scale": @1.2, @"text-color": @[@"rgb", @255, @0, @0] , @"text-font" : @[ @"literal", @[ @"DIN Offc Pro Bold", @"Arial Unicode MS Bold" ]]} ]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); + } + { MGLAttributedExpression *attribute1 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"foo"] fontNames:nil - fontSize:@(1.2)]; + fontScale:@(1.2)]; MGLAttributedExpression *attribute2 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"biz"] fontNames:nil - fontSize:@(1.0)]; + fontScale:@(1.0)]; MGLAttributedExpression *attribute3 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"bar"] fontNames:nil - fontSize:@(0.8)]; + fontScale:@(0.8)]; MGLAttributedExpression *attribute4 = [MGLAttributedExpression attributedExpression:[NSExpression expressionForConstantValue:@"\n"] fontNames:@[] - fontSize:nil]; + fontScale:nil]; NSExpression *expression = [NSExpression mgl_expressionForAttributedExpressions:@[MGLConstantExpression(attribute1), MGLConstantExpression(attribute4), MGLConstantExpression(attribute2), diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm index 7f0ead7cab..86dc28eb04 100644 --- a/platform/darwin/test/MGLOfflineStorageTests.mm +++ b/platform/darwin/test/MGLOfflineStorageTests.mm @@ -1,6 +1,7 @@ #import <Mapbox/Mapbox.h> #import "MGLOfflineStorage_Private.h" +#import "NSBundle+MGLAdditions.h" #import "NSDate+MGLAdditions.h" #import <XCTest/XCTest.h> @@ -10,7 +11,6 @@ #pragma clang diagnostic ignored "-Wshadow" @interface MGLOfflineStorageTests : XCTestCase <MGLOfflineStorageDelegate> - @end @implementation MGLOfflineStorageTests @@ -21,8 +21,7 @@ appropriateForURL:nil create:NO error:nil]; - // Unit tests don't use the main bundle; use com.mapbox.ios.sdk instead. - NSString *bundleIdentifier = [NSBundle bundleForClass:[MGLMapView class]].bundleIdentifier; + NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier]; cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:bundleIdentifier]; cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:@".mapbox"]; XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:cacheDirectoryURL.path], @"Cache subdirectory should exist."); @@ -208,8 +207,8 @@ appropriateForURL:nil create:NO error:nil]; - // Unit tests don't use the main bundle; use com.mapbox.ios.sdk instead. - NSString *bundleIdentifier = [NSBundle bundleForClass:[MGLMapView class]].bundleIdentifier; + // As of iOS SDK 12.2 unit tests now have a bundle id: com.apple.dt.xctest.tool + NSString *bundleIdentifier = [NSBundle mgl_applicationBundleIdentifier]; cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:bundleIdentifier]; cacheDirectoryURL = [cacheDirectoryURL URLByAppendingPathComponent:@".mapbox"]; XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:cacheDirectoryURL.path], @"Cache subdirectory should exist."); diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm index 2f4206a96b..083b12bcc3 100644 --- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm +++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm @@ -1741,6 +1741,75 @@ XCTAssertThrowsSpecificNamed(layer.textPitchAlignment = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes."); } + // text-radial-offset + { + XCTAssertTrue(rawLayer->getTextRadialOffset().isUndefined(), + @"text-radial-offset should be unset initially."); + NSExpression *defaultExpression = layer.textRadialOffset; + + NSExpression *constantExpression = [NSExpression expressionWithFormat:@"1"]; + layer.textRadialOffset = constantExpression; + mbgl::style::PropertyValue<float> propertyValue = { 1.0 }; + XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue, + @"Setting textRadialOffset to a constant value expression should update text-radial-offset."); + XCTAssertEqualObjects(layer.textRadialOffset, constantExpression, + @"textRadialOffset should round-trip constant value expressions."); + + constantExpression = [NSExpression expressionWithFormat:@"1"]; + NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}]; + layer.textRadialOffset = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression<float>( + step(zoom(), literal(1.0), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue, + @"Setting textRadialOffset to a camera expression should update text-radial-offset."); + XCTAssertEqualObjects(layer.textRadialOffset, functionExpression, + @"textRadialOffset should round-trip camera expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}]; + layer.textRadialOffset = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression<float>( + interpolate(linear(), number(get("keyName")), 18.0, literal(1.0)) + ); + } + + XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue, + @"Setting textRadialOffset to a data expression should update text-radial-offset."); + NSExpression *pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(CAST(keyName, 'NSNumber'), 'linear', nil, %@)", @{@18: constantExpression}]; + XCTAssertEqualObjects(layer.textRadialOffset, pedanticFunctionExpression, + @"textRadialOffset should round-trip data expressions."); + + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}]; + layer.textRadialOffset = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression<float>( + interpolate(linear(), zoom(), 10.0, interpolate(linear(), number(get("keyName")), 18.0, literal(1.0))) + ); + } + + XCTAssertEqual(rawLayer->getTextRadialOffset(), propertyValue, + @"Setting textRadialOffset to a camera-data expression should update text-radial-offset."); + pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}]; + XCTAssertEqualObjects(layer.textRadialOffset, pedanticFunctionExpression, + @"textRadialOffset should round-trip camera-data expressions."); + + layer.textRadialOffset = nil; + XCTAssertTrue(rawLayer->getTextRadialOffset().isUndefined(), + @"Unsetting textRadialOffset should return text-radial-offset to the default value."); + XCTAssertEqualObjects(layer.textRadialOffset, defaultExpression, + @"textRadialOffset should return the default value after being unset."); + } + // text-rotate { XCTAssertTrue(rawLayer->getTextRotate().isUndefined(), @@ -1892,6 +1961,50 @@ @"textTransform should return the default value after being unset."); } + // text-variable-anchor + { + XCTAssertTrue(rawLayer->getTextVariableAnchor().isUndefined(), + @"text-variable-anchor should be unset initially."); + NSExpression *defaultExpression = layer.textVariableAnchor; + + NSExpression *constantExpression = [NSExpression expressionWithFormat:@"{'top','bottom'}"]; + layer.textVariableAnchor = constantExpression; + mbgl::style::PropertyValue<std::vector<mbgl::style::SymbolAnchorType>> propertyValue = { { mbgl::style::SymbolAnchorType::Top, mbgl::style::SymbolAnchorType::Bottom } }; + XCTAssertEqual(rawLayer->getTextVariableAnchor(), propertyValue, + @"Setting textVariableAnchor to a constant value expression should update text-variable-anchor."); + XCTAssertEqualObjects(layer.textVariableAnchor, constantExpression, + @"textVariableAnchor should round-trip constant value expressions."); + + constantExpression = [NSExpression expressionWithFormat:@"{'top','bottom'}"]; + NSExpression *functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:($zoomLevel, %@, %@)", constantExpression, @{@18: constantExpression}]; + layer.textVariableAnchor = functionExpression; + + { + using namespace mbgl::style::expression::dsl; + propertyValue = mbgl::style::PropertyExpression<std::vector<mbgl::style::SymbolAnchorType>>( + step(zoom(), literal({"top", "bottom"}), 18.0, literal({"top", "bottom"})) + ); + } + + XCTAssertEqual(rawLayer->getTextVariableAnchor(), propertyValue, + @"Setting textVariableAnchor to a camera expression should update text-variable-anchor."); + XCTAssertEqualObjects(layer.textVariableAnchor, functionExpression, + @"textVariableAnchor should round-trip camera expressions."); + + + layer.textVariableAnchor = nil; + XCTAssertTrue(rawLayer->getTextVariableAnchor().isUndefined(), + @"Unsetting textVariableAnchor should return text-variable-anchor to the default value."); + XCTAssertEqualObjects(layer.textVariableAnchor, defaultExpression, + @"textVariableAnchor should return the default value after being unset."); + + functionExpression = [NSExpression expressionForKeyPath:@"bogus"]; + XCTAssertThrowsSpecificNamed(layer.textVariableAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes."); + functionExpression = [NSExpression expressionWithFormat:@"mgl_step:from:stops:(bogus, %@, %@)", constantExpression, @{@18: constantExpression}]; + functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: functionExpression}]; + XCTAssertThrowsSpecificNamed(layer.textVariableAnchor = functionExpression, NSException, NSInvalidArgumentException, @"MGLSymbolLayer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes."); + } + // icon-color { XCTAssertTrue(rawLayer->getIconColor().isUndefined(), @@ -2896,9 +3009,11 @@ [self testPropertyName:@"is-text-optional" isBoolean:YES]; [self testPropertyName:@"text-padding" isBoolean:NO]; [self testPropertyName:@"text-pitch-alignment" isBoolean:NO]; + [self testPropertyName:@"text-radial-offset" isBoolean:NO]; [self testPropertyName:@"text-rotation" isBoolean:NO]; [self testPropertyName:@"text-rotation-alignment" isBoolean:NO]; [self testPropertyName:@"text-transform" isBoolean:NO]; + [self testPropertyName:@"text-variable-anchor" isBoolean:NO]; [self testPropertyName:@"icon-color" isBoolean:NO]; [self testPropertyName:@"icon-halo-blur" isBoolean:NO]; [self testPropertyName:@"icon-halo-color" isBoolean:NO]; @@ -2949,6 +3064,7 @@ XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorTopRight].MGLTextAnchorValue, MGLTextAnchorTopRight); XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomLeft].MGLTextAnchorValue, MGLTextAnchorBottomLeft); XCTAssertEqual([NSValue valueWithMGLTextAnchor:MGLTextAnchorBottomRight].MGLTextAnchorValue, MGLTextAnchorBottomRight); + XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationAuto].MGLTextJustificationValue, MGLTextJustificationAuto); XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationLeft].MGLTextJustificationValue, MGLTextJustificationLeft); XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationCenter].MGLTextJustificationValue, MGLTextJustificationCenter); XCTAssertEqual([NSValue valueWithMGLTextJustification:MGLTextJustificationRight].MGLTextJustificationValue, MGLTextJustificationRight); diff --git a/platform/default/include/mbgl/map/map_snapshotter.hpp b/platform/default/include/mbgl/map/map_snapshotter.hpp index 2deb2b3cda..ccc3ee17f7 100644 --- a/platform/default/include/mbgl/map/map_snapshotter.hpp +++ b/platform/default/include/mbgl/map/map_snapshotter.hpp @@ -18,6 +18,7 @@ struct CameraOptions; class FileSource; class Size; class LatLngBounds; +class ResourceOptions; namespace style { class Style; @@ -25,15 +26,15 @@ class Style; class MapSnapshotter { public: - MapSnapshotter(FileSource* fileSource, - std::shared_ptr<Scheduler> scheduler, + MapSnapshotter(std::shared_ptr<Scheduler> scheduler, const std::pair<bool, std::string> style, const Size&, const float pixelRatio, const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, - const optional<std::string> cacheDir = {}, - const optional<std::string> localFontFamily = {}); + const optional<std::string> cacheDir, + const optional<std::string> localFontFamily, + const ResourceOptions&); ~MapSnapshotter(); diff --git a/platform/default/src/mbgl/gl/headless_frontend.cpp b/platform/default/src/mbgl/gl/headless_frontend.cpp index f3dae2dbc9..c311e2df41 100644 --- a/platform/default/src/mbgl/gl/headless_frontend.cpp +++ b/platform/default/src/mbgl/gl/headless_frontend.cpp @@ -20,7 +20,13 @@ HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, Scheduler& sch asyncInvalidate([this] { if (renderer && updateParameters) { mbgl::BackendScope guard { backend }; - renderer->render(*updateParameters); + + // onStyleImageMissing might be called during a render. The user implemented method + // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`. + // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is + // still using them. + auto updateParameters_ = updateParameters; + renderer->render(*updateParameters_); } }), renderer(std::make_unique<Renderer>(backend, pixelRatio, scheduler, mode, programCacheDir, localFontFamily)) { diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp index 415ef7befd..227a61d272 100644 --- a/platform/default/src/mbgl/map/map_snapshotter.cpp +++ b/platform/default/src/mbgl/map/map_snapshotter.cpp @@ -5,7 +5,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/style/style.hpp> #include <mbgl/util/event.hpp> #include <mbgl/map/transform.hpp> @@ -14,15 +14,15 @@ namespace mbgl { class MapSnapshotter::Impl { public: - Impl(FileSource*, - std::shared_ptr<Scheduler>, + Impl(std::shared_ptr<Scheduler>, const std::pair<bool, std::string> style, const Size&, const float pixelRatio, const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> programCacheDir, - const optional<std::string> localFontFamily = {}); + const optional<std::string> localFontFamily, + const ResourceOptions& resourceOptions); void setStyleURL(std::string styleURL); std::string getStyleURL() const; @@ -47,19 +47,20 @@ private: Map map; }; -MapSnapshotter::Impl::Impl(FileSource* fileSource, - std::shared_ptr<Scheduler> scheduler_, - const std::pair<bool, std::string> style, - const Size& size, - const float pixelRatio, - const optional<CameraOptions> cameraOptions, - const optional<LatLngBounds> region, - const optional<std::string> programCacheDir, - const optional<std::string> localFontFamily) - : scheduler(std::move(scheduler_)) - , frontend(size, pixelRatio, *scheduler, programCacheDir, GLContextMode::Unique, localFontFamily) - , map(frontend, MapObserver::nullObserver(), size, pixelRatio, *fileSource, *scheduler, MapOptions().withMapMode(MapMode::Static)) { - +MapSnapshotter::Impl::Impl(std::shared_ptr<Scheduler> scheduler_, + const std::pair<bool, std::string> style, + const Size& size, + const float pixelRatio, + const optional<CameraOptions> cameraOptions, + const optional<LatLngBounds> region, + const optional<std::string> programCacheDir, + const optional<std::string> localFontFamily, + const ResourceOptions& resourceOptions) + : scheduler(std::move(scheduler_)) + , frontend(size, pixelRatio, *scheduler, programCacheDir, GLContextMode::Unique, localFontFamily) + , map(frontend, MapObserver::nullObserver(), *scheduler, + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + resourceOptions) { if (style.first) { map.getStyle().loadJSON(style.second); } else{ @@ -142,7 +143,7 @@ void MapSnapshotter::Impl::setSize(Size size) { } Size MapSnapshotter::Impl::getSize() const { - return map.getSize(); + return map.getMapOptions().size(); } void MapSnapshotter::Impl::setCameraOptions(CameraOptions cameraOptions) { @@ -164,17 +165,18 @@ LatLngBounds MapSnapshotter::Impl::getRegion() const { return map.latLngBoundsForCamera(getCameraOptions()); } -MapSnapshotter::MapSnapshotter(FileSource* fileSource, - std::shared_ptr<Scheduler> scheduler, +MapSnapshotter::MapSnapshotter(std::shared_ptr<Scheduler> scheduler, const std::pair<bool, std::string> style, const Size& size, const float pixelRatio, const optional<CameraOptions> cameraOptions, const optional<LatLngBounds> region, const optional<std::string> programCacheDir, - const optional<std::string> localFontFamily) - : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>("Map Snapshotter", fileSource, std::move(scheduler), style, size, pixelRatio, cameraOptions, region, programCacheDir, localFontFamily)) { -} + const optional<std::string> localFontFamily, + const ResourceOptions& resourceOptions) + : impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>( + "Map Snapshotter", std::move(scheduler), style, size, pixelRatio, cameraOptions, + region, programCacheDir, localFontFamily, resourceOptions.clone())) {} MapSnapshotter::~MapSnapshotter() = default; diff --git a/platform/default/src/mbgl/storage/default_file_source.cpp b/platform/default/src/mbgl/storage/default_file_source.cpp index 32eb8b3d58..4d812044cf 100644 --- a/platform/default/src/mbgl/storage/default_file_source.cpp +++ b/platform/default/src/mbgl/storage/default_file_source.cpp @@ -201,9 +201,9 @@ private: }; DefaultFileSource::DefaultFileSource(const std::string& cachePath, - const std::string& assetRoot, + const std::string& assetPath, uint64_t maximumCacheSize) - : DefaultFileSource(cachePath, std::make_unique<AssetFileSource>(assetRoot), maximumCacheSize) { + : DefaultFileSource(cachePath, std::make_unique<AssetFileSource>(assetPath), maximumCacheSize) { } DefaultFileSource::DefaultFileSource(const std::string& cachePath, diff --git a/platform/default/src/mbgl/storage/file_source.cpp b/platform/default/src/mbgl/storage/file_source.cpp new file mode 100644 index 0000000000..a7bbe82f5a --- /dev/null +++ b/platform/default/src/mbgl/storage/file_source.cpp @@ -0,0 +1,15 @@ +#include <mbgl/storage/resource_options.hpp> +#include <mbgl/storage/default_file_source.hpp> + +#include <memory> + +namespace mbgl { + +std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) { + auto fileSource = std::make_shared<DefaultFileSource>(options.cachePath(), options.assetPath()); + fileSource->setAccessToken(options.accessToken()); + fileSource->setAPIBaseURL(options.baseURL()); + return fileSource; +} + +} // namespace mbgl diff --git a/platform/glfw/glfw_renderer_frontend.cpp b/platform/glfw/glfw_renderer_frontend.cpp index 73205f1c56..9c5320cc78 100644 --- a/platform/glfw/glfw_renderer_frontend.cpp +++ b/platform/glfw/glfw_renderer_frontend.cpp @@ -32,7 +32,12 @@ void GLFWRendererFrontend::render() { mbgl::BackendScope guard { glfwView, mbgl::BackendScope::ScopeType::Implicit }; - renderer->render(*updateParameters); + // onStyleImageMissing might be called during a render. The user implemented method + // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`. + // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is + // still using them. + auto updateParameters_ = updateParameters; + renderer->render(*updateParameters_); } mbgl::Renderer* GLFWRendererFrontend::getRenderer() { diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index e768851a53..601642cfa6 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -385,7 +385,7 @@ GLFWView::makeImage(const std::string& id, int width, int height, float pixelRat void GLFWView::nextOrientation() { using NO = mbgl::NorthOrientation; - switch (map->getNorthOrientation()) { + switch (map->getMapOptions().northOrientation()) { case NO::Upwards: map->setNorthOrientation(NO::Rightwards); break; case NO::Rightwards: map->setNorthOrientation(NO::Downwards); break; case NO::Downwards: map->setNorthOrientation(NO::Leftwards); break; diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index 38a41cbf18..fb7c2b4ffb 100644 --- a/platform/glfw/main.cpp +++ b/platform/glfw/main.cpp @@ -10,7 +10,7 @@ #include <mbgl/style/style.hpp> #include <mbgl/renderer/renderer.hpp> -#include <args/args.hxx> +#include <args.hxx> #include <csignal> #include <fstream> @@ -93,23 +93,26 @@ int main(int argc, char *argv[]) { GLFWView backend(fullscreen, benchmark); view = &backend; - mbgl::DefaultFileSource fileSource(cacheDB, "."); - if (!settings.online) { - fileSource.setOnlineStatus(false); - mbgl::Log::Warning(mbgl::Event::Setup, "Application is offline. Press `O` to toggle online status."); - } - // Set access token if present - const char *token = getenv("MAPBOX_ACCESS_TOKEN"); - if (token == nullptr) { + std::string token(getenv("MAPBOX_ACCESS_TOKEN") ?: ""); + if (token.empty()) { mbgl::Log::Warning(mbgl::Event::Setup, "no access token set. mapbox.com tiles won't work."); - } else { - fileSource.setAccessToken(std::string(token)); + } + + mbgl::ResourceOptions resourceOptions; + resourceOptions.withCachePath(cacheDB).withAccessToken(token); + + auto fileSource = std::static_pointer_cast<mbgl::DefaultFileSource>(mbgl::FileSource::getSharedFileSource(resourceOptions)); + if (!settings.online) { + fileSource->setOnlineStatus(false); + mbgl::Log::Warning(mbgl::Event::Setup, "Application is offline. Press `O` to toggle online status."); } mbgl::ThreadPool threadPool(4); GLFWRendererFrontend rendererFrontend { std::make_unique<mbgl::Renderer>(backend, view->getPixelRatio(), threadPool), backend }; - mbgl::Map map(rendererFrontend, backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool, mbgl::MapOptions()); + + mbgl::Map map(rendererFrontend, backend, threadPool, + mbgl::MapOptions().withSize(view->getSize()).withPixelRatio(view->getPixelRatio()), resourceOptions); backend.setMap(&map); @@ -124,9 +127,9 @@ int main(int argc, char *argv[]) { .withPitch(settings.pitch)); map.setDebug(mbgl::MapDebugOptions(settings.debug)); - view->setOnlineStatusCallback([&settings, &fileSource]() { + view->setOnlineStatusCallback([&settings, fileSource]() { settings.online = !settings.online; - fileSource.setOnlineStatus(settings.online); + fileSource->setOnlineStatus(settings.online); mbgl::Log::Info(mbgl::Event::Setup, "Application is %s. Press `O` to toggle online status.", settings.online ? "online" : "offline"); }); @@ -144,13 +147,13 @@ int main(int argc, char *argv[]) { mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name); }); - view->setPauseResumeCallback([&fileSource] () { + view->setPauseResumeCallback([fileSource] () { static bool isPaused = false; if (isPaused) { - fileSource.resume(); + fileSource->resume(); } else { - fileSource.pause(); + fileSource->pause(); } isPaused = !isPaused; diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a1ab7c949a..d7a68c40b4 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -4,15 +4,29 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## 4.10.0 +### Styles and rendering + * Client-side text rendering of CJK ideographs is now enabled by default. ([#13988](https://github.com/mapbox/mapbox-gl-native/pull/13988)) -* Added an MGLMapView.prefetchesTiles property that you can disable if you don’t want to prefetch simplified tiles as a performance optimization. ([#14031](https://github.com/mapbox/mapbox-gl-native/pull/14031)) * Fixed an issue that caused `MGL_FUNCTION` to ignore multiple formatting parameters when passed a `format` function as parameter. ([#14064](https://github.com/mapbox/mapbox-gl-native/pull/14064)) +* Added `mgl_attributed:` expression operator, which concatenates `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094)) +* Fixed an issue that caused conditional expressions to crash when passed nested conditional expressions as parameters. ([#14181](https://github.com/mapbox/mapbox-gl-native/pull/14181)) +* Added `-[MGLMapViewDelegate mapView:didFailToLoadImage:]` to load missing symbol icons in the style if they are not found. ([#14302](https://github.com/mapbox/mapbox-gl-native/pull/14302)) + +### Packaging + * Added a Galician localization. ([#14095](https://github.com/mapbox/mapbox-gl-native/pull/14095)) -* Added `mgl_attributed:` expression operator, which concatenate `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094)) +* Added support for building with Xcode 10.2 / iOS SDK 12.2. ([#14241](https://github.com/mapbox/mapbox-gl-native/pull/14241)) -### User interaction +### Offline maps + +* Fixed a bug that caused offline packs created prior to v4.0.0 to be marked as `MGLOfflinePackStateInactive`. ([#14188](https://github.com/mapbox/mapbox-gl-native/pull/14188)) + +### Other changes + +* Added `MGLOrnamentPosition` enum and margin properties to customize scale bar, compass, logo, and attribution position within the map view. ([#13911](https://github.com/mapbox/mapbox-gl-native/pull/13911)) +* Added an `MGLMapView.prefetchesTiles` property to configure lower-resolution tile prefetching behavior. ([#14031](https://github.com/mapbox/mapbox-gl-native/pull/14031)) +* Speculatively fixed a performance issue seen on iOS 12.2, when an `MGLMapView` is repeatedly removed and re-added in a view hierarchy. ([#14264](https://github.com/mapbox/mapbox-gl-native/pull/14264)) -* Added `MGLOrnamentPosition` enum and margins methods to customize MGLMapView's scale bar, compass, logo and attribution position. ([#13911](https://github.com/mapbox/mapbox-gl-native/pull/13911)) ## 4.9.0 - February 27, 2019 diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m index 7ec45de072..0b32df55b4 100644 --- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m +++ b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m @@ -405,7 +405,6 @@ static const CGFloat kAnnotationScale = 0.125f; NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer"; - CGFloat epsilon = 0.0000001; CGSize size = self.mapView.bounds.size; CGSize annotationSize = CGSizeMake(40.0, 40.0); diff --git a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm index e422c46cf4..60d5fc6c9a 100644 --- a/platform/ios/Integration Tests/MGLCameraTransitionTests.mm +++ b/platform/ios/Integration Tests/MGLCameraTransitionTests.mm @@ -277,7 +277,7 @@ // Now set another coordinate. MGLMapCamera *camera = [MGLMapCamera cameraLookingAtCenterCoordinate:target2 - fromDistance:altitude + altitude:altitude pitch:0.0 heading:0.0]; diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec index bff5531290..4030511c1b 100644 --- a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.10.0-alpha.2' + version = '4.10.0-beta.2' m.name = 'Mapbox-iOS-SDK-snapshot-dynamic' m.version = "#{version}-snapshot" diff --git a/platform/ios/Mapbox-iOS-SDK-stripped.podspec b/platform/ios/Mapbox-iOS-SDK-stripped.podspec index 9a32524ef0..d3a6d698a7 100644 --- a/platform/ios/Mapbox-iOS-SDK-stripped.podspec +++ b/platform/ios/Mapbox-iOS-SDK-stripped.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.10.0-alpha.2' + version = '4.10.0-beta.2' m.name = 'Mapbox-iOS-SDK-stripped' m.version = "#{version}-stripped" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 1cbd82c5e4..f8dc21a155 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.10.0-alpha.2' + version = '4.10.0-beta.2' m.name = 'Mapbox-iOS-SDK' m.version = version diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 9c506cadfa..8d936d6a25 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -103,6 +103,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { MBXSettingsMiscellaneousToggleTwoMaps, MBXSettingsMiscellaneousLocalizeLabels, MBXSettingsMiscellaneousShowSnapshots, + MBXSettingsMiscellaneousMissingIcon, MBXSettingsMiscellaneousShouldLimitCameraChanges, MBXSettingsMiscellaneousShowCustomLocationManager, MBXSettingsMiscellaneousOrnamentsPlacement, @@ -499,6 +500,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { [NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")], [NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])], @"Show Snapshots", + @"Missing Icon", [NSString stringWithFormat:@"%@ Camera Changes", (_shouldLimitCameraChanges ? @"Unlimit" : @"Limit")], @"View Route Simulation", @"Ornaments Placement", @@ -746,6 +748,11 @@ CLLocationCoordinate2D randomWorldCoordinate() { [self performSegueWithIdentifier:@"ShowSnapshots" sender:nil]; break; } + case MBXSettingsMiscellaneousMissingIcon: + { + [self loadMissingIcon]; + break; + } case MBXSettingsMiscellaneousShowCustomLocationManager: { [self performSegueWithIdentifier:@"ShowCustomLocationManger" sender:nil]; @@ -1718,6 +1725,19 @@ CLLocationCoordinate2D randomWorldCoordinate() { [self.mapView addAnnotation:line]; } +- (void)loadMissingIcon +{ + self.mapView.centerCoordinate = CLLocationCoordinate2DMake(0, 0); + self.mapView.zoomLevel = 1; + NSURL *customStyleJSON = [[NSBundle mainBundle] URLForResource:@"missing_icon" withExtension:@"json"]; + [self.mapView setStyleURL:customStyleJSON]; +} + +- (UIImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName { + UIImage *backupImage = [UIImage imageNamed:@"AppIcon"]; + return backupImage; +} + - (void)printTelemetryLogFile { NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil]; diff --git a/platform/ios/app/missing_icon.json b/platform/ios/app/missing_icon.json new file mode 100644 index 0000000000..5da4125990 --- /dev/null +++ b/platform/ios/app/missing_icon.json @@ -0,0 +1,40 @@ +{ + "version": 8, + "name": "Mapbox Streets", + "sprite": "mapbox://sprites/mapbox/streets-v8", + "glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf", + "sources": { + "point": { + "type": "geojson", + "data": { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [0, 0] + } + } + } + }, + "layers": [{ + "id": "bg", + "type": "background", + "paint": { + "background-color": "#f00" + } + }, { + "id": "point", + "type": "circle", + "source": "point", + "paint": { + "circle-radius": 100 + } + }, { + "id": "icon", + "type": "symbol", + "source": "point", + "layout": { + "icon-image": "missing-icon" + } + }] +} diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 73394ff6ed..1acf587cda 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -418,5 +418,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index b24bcbe110..1fe22d2c7d 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -98,9 +98,6 @@ 35136D4D1D4277FC00C20EFD /* MGLSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 35136D4A1D4277FC00C20EFD /* MGLSource.h */; settings = {ATTRIBUTES = (Public, ); }; }; 35136D4E1D4277FC00C20EFD /* MGLSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35136D4B1D4277FC00C20EFD /* MGLSource.mm */; }; 35136D4F1D4277FC00C20EFD /* MGLSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35136D4B1D4277FC00C20EFD /* MGLSource.mm */; }; - 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */; }; - 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */; }; - 35305D4A1D22AA6A0007D005 /* NSData+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */; }; 3538AA1D1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3538AA1E1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */; }; @@ -179,7 +176,6 @@ 35E0CFE71D3E501500188327 /* MGLStyle_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */; }; 35E1A4D81D74336F007AA97F /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */; }; 35E1A4D91D74336F007AA97F /* MGLValueEvaluator.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */; }; - 35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */; }; 35E79F201D41266300957B9E /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */; }; 35E79F211D41266300957B9E /* MGLStyleLayer_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */; }; 3E6465D62065767A00685536 /* LimeGreenStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */; }; @@ -223,7 +219,6 @@ 40834BEE1FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; }; 40834BEF1FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; }; 40834BF01FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; }; - 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; }; 40834BF21FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; }; 40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; }; 40834BF51FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; }; @@ -242,7 +237,7 @@ 40834C021FE05E1800C1BD0D /* MMEEventsConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB21FE05D6D00C1BD0D /* MMEEventsConfiguration.m */; }; 40834C031FE05E1800C1BD0D /* MMEEventsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BA41FE05D6B00C1BD0D /* MMEEventsManager.m */; }; 40834C041FE05E1800C1BD0D /* MMELocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB81FE05D6D00C1BD0D /* MMELocationManager.m */; }; - 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */; }; + 40834C051FE05E1800C1BD0D /* MMEDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */; }; 40834C061FE05E1800C1BD0D /* MMENSURLSessionWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */; }; 40834C071FE05E1800C1BD0D /* MMETimerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */; }; 40834C091FE05E1800C1BD0D /* MMETypes.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */; }; @@ -340,7 +335,6 @@ 55E5666221C2A2080008B8B5 /* MMELocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BB31FE05D6D00C1BD0D /* MMELocationManager.h */; }; 55E5666321C2A2080008B8B5 /* MMEMetrics.h in Headers */ = {isa = PBXBuildFile; fileRef = ACD024552187EAAF00D8C8A7 /* MMEMetrics.h */; }; 55E5666421C2A2080008B8B5 /* MMEMetricsManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ACD024562187EAAF00D8C8A7 /* MMEMetricsManager.h */; }; - 55E5666521C2A2080008B8B5 /* MMENSDateWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */; }; 55E5666621C2A2080008B8B5 /* MMENSURLSessionWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */; }; 55E5666721C2A2080008B8B5 /* MMETimerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC91FE05D7000C1BD0D /* MMETimerManager.h */; }; 55E5666821C2A2080008B8B5 /* MMETypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BB61FE05D6D00C1BD0D /* MMETypes.h */; }; @@ -451,7 +445,6 @@ 96E516F12000596800A02306 /* NSString+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848171CBAFA6200AB86E3 /* NSString+MGLAdditions.h */; }; 96E516F22000596D00A02306 /* NSException+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848141CBAFA6200AB86E3 /* NSException+MGLAdditions.h */; }; 96E516F32000597100A02306 /* NSDictionary+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */; }; - 96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */; }; 96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96E516F6200059EC00A02306 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */; }; 96E516F720005A2700A02306 /* MGLAnnotationContainerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */; }; @@ -464,6 +457,9 @@ 96E5170420005A6B00A02306 /* SMCalloutView.h in Headers */ = {isa = PBXBuildFile; fileRef = DA8848891CBB037E00AB86E3 /* SMCalloutView.h */; }; 96ED34DE22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */; }; 96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */; }; + 9C188C4F2242C95A0022FA55 /* MMEDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */; }; + 9C188C502242C96F0022FA55 /* MMEDate.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BC51FE05D6F00C1BD0D /* MMEDate.h */; }; + A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */ = {isa = PBXBuildFile; fileRef = A4F3FB1C2254865900A30170 /* missing_icon.json */; }; AC1B0916221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */; }; AC1B0917221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */ = {isa = PBXBuildFile; fileRef = AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */; }; AC1B0918221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */ = {isa = PBXBuildFile; fileRef = AC1B0915221CA14C00DB56C8 /* CLLocationManager+MMEMobileEvents.m */; }; @@ -914,8 +910,6 @@ 35136D441D42275100C20EFD /* MGLSymbolStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSymbolStyleLayer.mm; sourceTree = "<group>"; }; 35136D4A1D4277FC00C20EFD /* MGLSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLSource.h; sourceTree = "<group>"; }; 35136D4B1D4277FC00C20EFD /* MGLSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLSource.mm; sourceTree = "<group>"; }; - 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+MGLAdditions.h"; sourceTree = "<group>"; }; - 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSData+MGLAdditions.mm"; sourceTree = "<group>"; }; 3538AA1B1D542239008EC33D /* MGLForegroundStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLForegroundStyleLayer.h; sourceTree = "<group>"; }; 3538AA1C1D542239008EC33D /* MGLForegroundStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLForegroundStyleLayer.mm; sourceTree = "<group>"; }; 353933F11D3FB753003F57D7 /* MGLCircleStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCircleStyleLayer.h; sourceTree = "<group>"; }; @@ -964,7 +958,6 @@ 35DE35531EB7CBA8004917C5 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Localizable.stringsdict; sourceTree = "<group>"; }; 35E0CFE51D3E501500188327 /* MGLStyle_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyle_Private.h; sourceTree = "<group>"; }; 35E1A4D71D74336F007AA97F /* MGLValueEvaluator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLValueEvaluator.h; sourceTree = "<group>"; }; - 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLNSDataAdditionsTests.m; sourceTree = "<group>"; }; 35E79F1F1D41266300957B9E /* MGLStyleLayer_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLStyleLayer_Private.h; sourceTree = "<group>"; }; 36F1153C1D46080700878E1A /* libmbgl-platform-ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libmbgl-platform-ios.a"; path = "build/Debug-iphoneos/libmbgl-platform-ios.a"; sourceTree = "<group>"; }; 3E6465D42065767A00685536 /* LimeGreenStyleLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LimeGreenStyleLayer.m; path = ../../darwin/app/LimeGreenStyleLayer.m; sourceTree = "<group>"; }; @@ -1012,7 +1005,7 @@ 40834BB91FE05D6E00C1BD0D /* MMETimerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETimerManager.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.m"; sourceTree = SOURCE_ROOT; }; 40834BBA1FE05D6E00C1BD0D /* MMEEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEvent.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.h"; sourceTree = SOURCE_ROOT; }; 40834BBB1FE05D6E00C1BD0D /* MMEEventsConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEEventsConfiguration.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventsConfiguration.h"; sourceTree = SOURCE_ROOT; }; - 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSDateWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.m"; sourceTree = SOURCE_ROOT; }; + 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEDate.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.m"; sourceTree = SOURCE_ROOT; }; 40834BBD1FE05D6E00C1BD0D /* MMETypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMETypes.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.m"; sourceTree = SOURCE_ROOT; }; 40834BBE1FE05D6E00C1BD0D /* MMEUIApplicationWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUIApplicationWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.h"; sourceTree = SOURCE_ROOT; }; 40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEUniqueIdentifier.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEUniqueIdentifier.h"; sourceTree = SOURCE_ROOT; }; @@ -1020,7 +1013,7 @@ 40834BC21FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CLLocation+MMEMobileEvents.h"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.h"; sourceTree = SOURCE_ROOT; }; 40834BC31FE05D6F00C1BD0D /* CLLocation+MMEMobileEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CLLocation+MMEMobileEvents.m"; path = "vendor/mapbox-events-ios/MapboxMobileEvents/CLLocation+MMEMobileEvents.m"; sourceTree = SOURCE_ROOT; }; 40834BC41FE05D6F00C1BD0D /* MMECategoryLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMECategoryLoader.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMECategoryLoader.m"; sourceTree = SOURCE_ROOT; }; - 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENSDateWrapper.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.h"; sourceTree = SOURCE_ROOT; }; + 40834BC51FE05D6F00C1BD0D /* MMEDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMEDate.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h"; sourceTree = SOURCE_ROOT; }; 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMENSURLSessionWrapper.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.m"; sourceTree = SOURCE_ROOT; }; 40834BC71FE05D7000C1BD0D /* MMEEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MMEEvent.m; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMEEvent.m"; sourceTree = SOURCE_ROOT; }; 40834BC81FE05D7000C1BD0D /* MMENamespacedDependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MMENamespacedDependencies.h; path = "vendor/mapbox-events-ios/MapboxMobileEvents/MMENamespacedDependencies.h"; sourceTree = SOURCE_ROOT; }; @@ -1151,6 +1144,7 @@ 96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewDirectionTests.mm; sourceTree = "<group>"; }; 96F017292118FBAE00892778 /* MGLMapView_Experimental.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Experimental.h; sourceTree = "<group>"; }; 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = "<group>"; }; + A4F3FB1C2254865900A30170 /* missing_icon.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = missing_icon.json; sourceTree = "<group>"; }; AC1B0914221CA14500DB56C8 /* CLLocationManager+MMEMobileEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "CLLocationManager+MMEMobileEvents.h"; path = "../vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.h"; sourceTree = "<group>"; }; AC1B0915221CA14C00DB56C8 /* CLLocationManager+MMEMobileEvents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "CLLocationManager+MMEMobileEvents.m"; path = "../vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.m"; sourceTree = "<group>"; }; AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTelemetryConfig.h; sourceTree = "<group>"; }; @@ -1774,8 +1768,8 @@ ACD024572187EAAF00D8C8A7 /* MMEMetrics.m */, ACD024562187EAAF00D8C8A7 /* MMEMetricsManager.h */, ACD024542187EAAF00D8C8A7 /* MMEMetricsManager.m */, - 40834BC51FE05D6F00C1BD0D /* MMENSDateWrapper.h */, - 40834BBC1FE05D6E00C1BD0D /* MMENSDateWrapper.m */, + 40834BC51FE05D6F00C1BD0D /* MMEDate.h */, + 40834BBC1FE05D6E00C1BD0D /* MMEDate.m */, 40834BAA1FE05D6C00C1BD0D /* MMENSURLSessionWrapper.h */, 40834BC61FE05D7000C1BD0D /* MMENSURLSessionWrapper.m */, 40834BC91FE05D7000C1BD0D /* MMETimerManager.h */, @@ -1891,6 +1885,7 @@ children = ( 353BAEF51D646370009A8DA9 /* amsterdam.geojson */, DA1DC96C1CB6C6CE006E619F /* points.geojson */, + A4F3FB1C2254865900A30170 /* missing_icon.json */, DA1DC96D1CB6C6CE006E619F /* polyline.geojson */, 1F26B6C220E1A351007BCC21 /* simple_route.json */, DA1DC96F1CB6C6CE006E619F /* threestates.geojson */, @@ -2041,7 +2036,6 @@ 96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */, 16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */, 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */, - 35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */, 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */, 96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */, DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */, @@ -2318,8 +2312,6 @@ 3510FFE91D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm */, 3510FFF71D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h */, 3510FFF81D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm */, - 35305D461D22AA450007D005 /* NSData+MGLAdditions.h */, - 35305D471D22AA450007D005 /* NSData+MGLAdditions.mm */, 353AFA121D65AB17005A69F4 /* NSDate+MGLAdditions.h */, 353AFA131D65AB17005A69F4 /* NSDate+MGLAdditions.mm */, 408AA8551DAEDA0800022900 /* NSDictionary+MGLAdditions.h */, @@ -2461,6 +2453,7 @@ DD0902AB1DB192A800C5BDCE /* MGLNetworkConfiguration.h in Headers */, 35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */, 0778DD431F67556700A73B34 /* MGLComputedShapeSource.h in Headers */, + 9C188C502242C96F0022FA55 /* MMEDate.h in Headers */, 1F6A82A221360F9D00BA5B41 /* MGLLoggingConfiguration.h in Headers */, AC1B0916221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.h in Headers */, DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */, @@ -2530,7 +2523,6 @@ DA72620B1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */, 404C26E71D89C55D000AA13D /* MGLTileSource_Private.h in Headers */, DA88485C1CBAFB9800AB86E3 /* MGLFaux3DUserLocationAnnotationView.h in Headers */, - 35305D4A1D22AA6A0007D005 /* NSData+MGLAdditions.h in Headers */, 359F57461D2FDDA6005217F1 /* MGLUserLocationAnnotationView_Private.h in Headers */, 404C26E21D89B877000AA13D /* MGLTileSource.h in Headers */, DA8847FD1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h in Headers */, @@ -2580,7 +2572,6 @@ 55E5666221C2A2080008B8B5 /* MMELocationManager.h in Headers */, 55E5666321C2A2080008B8B5 /* MMEMetrics.h in Headers */, 55E5666421C2A2080008B8B5 /* MMEMetricsManager.h in Headers */, - 55E5666521C2A2080008B8B5 /* MMENSDateWrapper.h in Headers */, 55E5666621C2A2080008B8B5 /* MMENSURLSessionWrapper.h in Headers */, 55E5666721C2A2080008B8B5 /* MMETimerManager.h in Headers */, 55E5666821C2A2080008B8B5 /* MMETypes.h in Headers */, @@ -2724,7 +2715,6 @@ 74CB5EB2219B252C00102936 /* MGLStyleLayerManager.h in Headers */, 9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */, 96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */, - 96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */, 96E516DD200054F200A02306 /* MGLPolygon_Private.h in Headers */, 353933F91D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */, 96E516EB2000560B00A02306 /* MGLUserLocation_Private.h in Headers */, @@ -2945,6 +2935,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, "zh-Hans", @@ -3014,6 +3005,7 @@ buildActionMask = 2147483647; files = ( DD4823771D94AE6C00EB71B7 /* numeric_filter_style.json in Resources */, + A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */, DA1DC9701CB6C6CE006E619F /* points.geojson in Resources */, 353BAEF61D646370009A8DA9 /* amsterdam.geojson in Resources */, DA1DC9711CB6C6CE006E619F /* polyline.geojson in Resources */, @@ -3177,7 +3169,6 @@ 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */, DAF25720201902BC00367EF5 /* MGLHillshadeStyleLayerTests.mm in Sources */, 353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */, - 35E208A71D24210F00EC9A46 /* MGLNSDataAdditionsTests.m in Sources */, DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */, 556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */, 4031ACFF1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift in Sources */, @@ -3189,6 +3180,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9C188C4F2242C95A0022FA55 /* MMEDate.m in Sources */, 35136D391D42271A00C20EFD /* MGLBackgroundStyleLayer.mm in Sources */, 3510FFEC1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.mm in Sources */, 40834C431FE05F7500C1BD0D /* TSKSPKIHashCache.m in Sources */, @@ -3224,7 +3216,6 @@ 40834BF31FE05E1800C1BD0D /* MMETimerManager.m in Sources */, 35136D421D42274500C20EFD /* MGLRasterStyleLayer.mm in Sources */, 3538AA1F1D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */, - 40834BF11FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */, AC1B0918221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */, 40834C461FE05F7500C1BD0D /* TSKPinFailureReport.m in Sources */, 406E99B91FFEFF1B00D9FFCC /* MMEEventLogReportViewController.m in Sources */, @@ -3272,7 +3263,6 @@ DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */, 92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */, ACD0245E2187EACB00D8C8A7 /* MMEMetrics.m in Sources */, - 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, 40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */, DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */, 357FE2DF1E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */, @@ -3361,7 +3351,7 @@ ACA65F5A2140697200537748 /* MMEDispatchManager.m in Sources */, 3538AA201D542239008EC33D /* MGLForegroundStyleLayer.mm in Sources */, DA00FC911D5EEB0D009AABC8 /* MGLAttributionInfo.mm in Sources */, - 40834C051FE05E1800C1BD0D /* MMENSDateWrapper.m in Sources */, + 40834C051FE05E1800C1BD0D /* MMEDate.m in Sources */, 40834C531FE05F7600C1BD0D /* TSKPinFailureReport.m in Sources */, AC1B0919221CA14D00DB56C8 /* CLLocationManager+MMEMobileEvents.m in Sources */, 40834BFA1FE05E1800C1BD0D /* CLLocation+MMEMobileEvents.m in Sources */, @@ -3405,7 +3395,6 @@ DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */, DA35A2A21CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */, 40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */, - 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, 357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */, 92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */, DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */, @@ -3693,7 +3682,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness"; }; @@ -3723,7 +3712,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness"; }; @@ -3878,6 +3867,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", "$(mbgl_filesource_INCLUDE_DIRECTORIES)", @@ -4007,7 +3997,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Integration Tests/integration-Bridging-Header.h"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 4.2; TARGETED_DEVICE_FAMILY = "1,2"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Integration Test Harness.app/Integration Test Harness"; }; @@ -4312,6 +4302,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREFIX_HEADER = "$SRCROOT/src/Mapbox-Prefix.pch"; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", "$(mbgl_filesource_INCLUDE_DIRECTORIES)", diff --git a/platform/ios/scripts/package.sh b/platform/ios/scripts/package.sh index 45aab45f3f..a37b3c7fda 100755 --- a/platform/ios/scripts/package.sh +++ b/platform/ios/scripts/package.sh @@ -11,6 +11,7 @@ PRODUCTS=${DERIVED_DATA} LOG_PATH=build/xcodebuild-$(date +"%Y-%m-%d_%H%M%S").log BUILD_FOR_DEVICE=${BUILD_DEVICE:-true} +BUILD_DOCS=${BUILD_DOCS:-true} SYMBOLS=${SYMBOLS:-YES} BUILDTYPE=${BUILDTYPE:-Debug} @@ -270,5 +271,7 @@ sed -i '' \ "${README}" cp ${README} "${OUTPUT}" -step "Generating API documentation…" -make idocument OUTPUT="${OUTPUT}/documentation" +if [ ${BUILD_DOCS} == true ]; then + step "Generating API documentation for ${BUILDTYPE} Build…" + make idocument OUTPUT="${OUTPUT}/documentation" +fi diff --git a/platform/ios/sdk-files.json b/platform/ios/sdk-files.json index 7dbfee1a2d..94f928b77e 100644 --- a/platform/ios/sdk-files.json +++ b/platform/ios/sdk-files.json @@ -1,6 +1,7 @@ { "//": "This file is generated. Do not edit. Regenerate it with scripts/generate-file-lists.js", "sources": [ + "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.m", "platform/darwin/src/MGLBackgroundStyleLayer.mm", "platform/darwin/src/NSComparisonPredicate+MGLAdditions.mm", "platform/ios/vendor/mapbox-events-ios/vendor/TrustKit/Pinning/TSKSPKIHashCache.m", @@ -36,7 +37,6 @@ "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.m", "platform/darwin/src/MGLRasterStyleLayer.mm", "platform/darwin/src/MGLForegroundStyleLayer.mm", - "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.m", "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.m", "platform/ios/vendor/mapbox-events-ios/vendor/TrustKit/Reporting/TSKPinFailureReport.m", "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEEventLogReportViewController.m", @@ -84,7 +84,6 @@ "platform/darwin/src/MGLCoordinateFormatter.m", "platform/darwin/src/MGLShapeOfflineRegion.mm", "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetrics.m", - "platform/darwin/src/NSData+MGLAdditions.mm", "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEUIApplicationWrapper.m", "platform/darwin/src/MGLStyle.mm", "platform/darwin/src/NSCoder+MGLAdditions.mm", @@ -243,6 +242,7 @@ "NSComparisonPredicate+MGLAdditions.h": "platform/darwin/src/NSComparisonPredicate+MGLAdditions.h", "MGLMapAccessibilityElement.h": "platform/ios/src/MGLMapAccessibilityElement.h", "MGLScaleBar.h": "platform/ios/src/MGLScaleBar.h", + "MMEDate.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h", "CLLocationManager+MMEMobileEvents.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/CLLocationManager+MMEMobileEvents.h", "NSString+MGLAdditions.h": "platform/darwin/src/NSString+MGLAdditions.h", "UIDevice+MGLAdditions.h": "platform/ios/src/UIDevice+MGLAdditions.h", @@ -279,7 +279,6 @@ "MGLOpenGLStyleLayer_Private.h": "platform/darwin/src/MGLOpenGLStyleLayer_Private.h", "MGLTileSource_Private.h": "platform/darwin/src/MGLTileSource_Private.h", "MGLFaux3DUserLocationAnnotationView.h": "platform/ios/src/MGLFaux3DUserLocationAnnotationView.h", - "NSData+MGLAdditions.h": "platform/darwin/src/NSData+MGLAdditions.h", "MGLUserLocationAnnotationView_Private.h": "platform/ios/src/MGLUserLocationAnnotationView_Private.h", "NSProcessInfo+MGLAdditions.h": "platform/darwin/src/NSProcessInfo+MGLAdditions.h", "MGLRasterTileSource_Private.h": "platform/darwin/src/MGLRasterTileSource_Private.h", @@ -323,7 +322,6 @@ "MMELocationManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMELocationManager.h", "MMEMetrics.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetrics.h", "MMEMetricsManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEMetricsManager.h", - "MMENSDateWrapper.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSDateWrapper.h", "MMENSURLSessionWrapper.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMENSURLSessionWrapper.h", "MMETimerManager.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETimerManager.h", "MMETypes.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMETypes.h", diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 1ef64a587b..589b7b547b 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -414,12 +414,12 @@ MGL_EXPORT IB_DESIGNABLE /** A Boolean value indicating whether the map should prefetch tiles. - When this property is set to YES, the map view prefetches loads tiles designed for a - low zoom level and displays them until receiving more detailed tiles for the current - zoom level. The prefetched tiles typically contain simplified versions of each shape, - improving the map view’s perceived performance. + When this property is set to `YES`, the map view prefetches tiles designed for + a low zoom level and displays them until receiving more detailed tiles for the + current zoom level. The prefetched tiles typically contain simplified versions + of each shape, improving the map view’s perceived performance. - The default value of this property is YES. + The default value of this property is `YES`. */ @property (nonatomic, assign) BOOL prefetchesTiles; @@ -434,17 +434,18 @@ MGL_EXPORT IB_DESIGNABLE #pragma mark Displaying the User’s Location /** - The object that this map view uses to start and stop the delivery of location-related - updates. + The object that this map view uses to start and stop the delivery of + location-related updates. - To receive the current user location, implement the `-[MGLMapViewDelegate mapView:didUpdateUserLocation:]` - and `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods. + To receive the current user location, implement the + `-[MGLMapViewDelegate mapView:didUpdateUserLocation:]` and + `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods. - If setting this property to `nil` or if no custom manager is provided this property - is set to the default location manager. + If setting this property to `nil` or if no custom manager is provided this + property is set to the default location manager. - `MGLMapView` uses a default location manager. If you want to substitute your own - location manager, you should do so by setting this property before setting + `MGLMapView` uses a default location manager. If you want to substitute your + own location manager, you should do so by setting this property before setting `showsUserLocation` to `YES`. To restore the default location manager, set this property to `nil`. */ diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index bda212de84..24e195c70a 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -11,7 +11,7 @@ #include <mbgl/util/platform.hpp> #include <mbgl/storage/reachability.h> #include <mbgl/util/default_thread_pool.hpp> -#include <mbgl/storage/default_file_source.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/network_status.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> @@ -156,6 +156,10 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1; const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10); +/// The number of view annotations (excluding the user location view) that must +/// be descendents of `MGLMapView` before presentsWithTransaction is enabled. +static const NSUInteger MGLPresentsWithTransactionAnnotationCount = 0; + /// An indication that the requested annotation was not found or is nonexistent. enum { MGLAnnotationTagNotFound = UINT32_MAX }; @@ -252,6 +256,7 @@ public: @property (nonatomic) MGLAnnotationContainerView *annotationContainerView; @property (nonatomic) MGLUserLocation *userLocation; @property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier; +@property (nonatomic) BOOL enablePresentsWithTransaction; /// Experimental rendering performance measurement. @property (nonatomic) BOOL experimental_enableFrameRateMeasurement; @@ -328,6 +333,9 @@ public: CFTimeInterval _frameCounterStartTime; NSInteger _frameCount; CFTimeInterval _frameDurations; + + BOOL _atLeastiOS_12_2_0; + } #pragma mark - Setup & Teardown - @@ -441,6 +449,7 @@ public: { _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent; _opaque = NO; + _atLeastiOS_12_2_0 = [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){12,2,0}]; BOOL background = [UIApplication sharedApplication].applicationState == UIApplicationStateBackground; if (!background) @@ -479,12 +488,18 @@ public: mbgl::MapOptions mapOptions; mapOptions.withMapMode(mbgl::MapMode::Continuous) + .withSize(self.size) + .withPixelRatio(config.scaleFactor) .withConstrainMode(mbgl::ConstrainMode::None) .withViewportMode(mbgl::ViewportMode::Default) .withCrossSourceCollisions(enableCrossSourceCollisions); + mbgl::ResourceOptions resourceOptions; + resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath]) + .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String); + NSAssert(!_mbglMap, @"_mbglMap should be NULL"); - _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *[config fileSource], *_mbglThreadPool, mapOptions); + _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, *_mbglThreadPool, mapOptions, resourceOptions); // start paused if in IB if (_isTargetingInterfaceBuilder || background) { @@ -675,6 +690,20 @@ public: static_cast<uint32_t>(self.glView.drawableHeight) }; } ++ (GLKView *)GLKViewWithFrame:(CGRect)frame context:(EAGLContext *)context opaque:(BOOL)opaque +{ + GLKView *glView = [[GLKView alloc] initWithFrame:frame context:context]; + glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + glView.enableSetNeedsDisplay = NO; + glView.drawableStencilFormat = GLKViewDrawableStencilFormat8; + glView.drawableDepthFormat = GLKViewDrawableDepthFormat16; + glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; + glView.layer.opaque = opaque; + glView.contentMode = UIViewContentModeCenter; + + return glView; +} + - (void)createGLView { if (_context) return; @@ -686,21 +715,14 @@ public: // create GL view // - _glView = [[GLKView alloc] initWithFrame:self.bounds context:_context]; - _glView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _glView.enableSetNeedsDisplay = NO; - _glView.drawableStencilFormat = GLKViewDrawableStencilFormat8; - _glView.drawableDepthFormat = GLKViewDrawableDepthFormat16; - _glView.contentScaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; - _glView.layer.opaque = _opaque; + _glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque]; _glView.delegate = self; CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); - eaglLayer.presentsWithTransaction = YES; + eaglLayer.presentsWithTransaction = NO; [_glView bindDrawable]; [self insertSubview:_glView atIndex:0]; - _glView.contentMode = UIViewContentModeCenter; } - (UIImage *)compassImage @@ -1095,6 +1117,13 @@ public: { MGLAssertIsMainThread(); + // Not "visible" - this isn't a full definition of visibility, but if + // the map view doesn't have a window then it *cannot* be visible. + if (!self.window) { + return; + } + + // Mismatched display link if (displayLink && displayLink != _displayLink) { return; } @@ -1107,8 +1136,28 @@ public: [self updateUserLocationAnnotationView]; [self updateAnnotationViews]; [self updateCalloutView]; - - [self.glView display]; + +#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY + // See https://github.com/mapbox/mapbox-gl-native/issues/14232 + // glClear can be blocked for 1 second. This code is an "escape hatch", + // an attempt to detect this situation and rebuild the GL views. + if (self.enablePresentsWithTransaction && _atLeastiOS_12_2_0) + { + CFTimeInterval before = CACurrentMediaTime(); + [self.glView display]; + CFTimeInterval after = CACurrentMediaTime(); + + if (after-before >= 1.0) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self emergencyRecreateGL]; + }); + } + } + else +#endif + { + [self.glView display]; + } } if (self.experimental_enableFrameRateMeasurement) @@ -1159,7 +1208,7 @@ public: BOOL isVisible = self.superview && self.window; if (isVisible && ! _displayLink) { - if (_mbglMap && self.mbglMap.getConstrainMode() == mbgl::ConstrainMode::None) + if (_mbglMap && self.mbglMap.getMapOptions().constrainMode() == mbgl::ConstrainMode::None) { self.mbglMap.setConstrainMode(mbgl::ConstrainMode::HeightOnly); } @@ -1225,15 +1274,96 @@ public: [self updateDisplayLinkPreferredFramesPerSecond]; } +- (void)setEnablePresentsWithTransaction:(BOOL)enablePresentsWithTransaction +{ + if (_enablePresentsWithTransaction == enablePresentsWithTransaction) + { + return; + } + + _enablePresentsWithTransaction = enablePresentsWithTransaction; + + // If the map is visible, change the layer property too + if (self.window) { + CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); + eaglLayer.presentsWithTransaction = enablePresentsWithTransaction; + } +} + +#ifdef MGL_RECREATE_GL_IN_AN_EMERGENCY +// See https://github.com/mapbox/mapbox-gl-native/issues/14232 +- (void)emergencyRecreateGL { + MGLLogError(@"Rendering took too long - creating GL views"); + + CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); + eaglLayer.presentsWithTransaction = NO; + + [self sleepGL:nil]; + + // Just performing a sleepGL/wakeGL pair isn't sufficient - in this case + // we can still get errors when calling bindDrawable. Here we completely + // recreate the GLKView + + [self.userLocationAnnotationView removeFromSuperview]; + [_glView removeFromSuperview]; + + _glView = [MGLMapView GLKViewWithFrame:self.bounds context:_context opaque:_opaque]; + _glView.delegate = self; + + [self insertSubview:_glView atIndex:0]; + + if (self.annotationContainerView) + { + [_glView insertSubview:self.annotationContainerView atIndex:0]; + } + + [self updateUserLocationAnnotationView]; + + // Do not bind...yet + + if (self.window) { + [self wakeGL:nil]; + CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); + eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction; + } + else { + MGLLogDebug(@"No window - skipping wakeGL"); + } +} +#endif + - (void)willMoveToWindow:(UIWindow *)newWindow { [super willMoveToWindow:newWindow]; [self refreshSupportedInterfaceOrientationsWithWindow:newWindow]; + + if (!newWindow) + { + // See https://github.com/mapbox/mapbox-gl-native/issues/14232 + // In iOS 12.2, CAEAGLLayer.presentsWithTransaction can cause dramatic + // slow down. The exact cause of this is unknown, but this work around + // appears to lessen the effects. + // + // Also, consider calling the new mbgl::Renderer::flush() + CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); + eaglLayer.presentsWithTransaction = NO; + + // Moved from didMoveToWindow + [self validateDisplayLink]; + } } - (void)didMoveToWindow { - [self validateDisplayLink]; [super didMoveToWindow]; + + if (self.window) + { + // See above comment + CAEAGLLayer *eaglLayer = MGL_OBJC_DYNAMIC_CAST(_glView.layer, CAEAGLLayer); + eaglLayer.presentsWithTransaction = self.enablePresentsWithTransaction; + + [self validateDisplayLink]; + } } - (void)didMoveToSuperview @@ -2508,10 +2638,15 @@ public: { MGLLogInfo(@"Resetting the map to the current style’s default viewport."); auto camera = self.mbglMap.getStyle().getDefaultCamera(); - CGFloat pitch = *camera.pitch; - CLLocationDirection heading = mbgl::util::wrap(*camera.bearing, 0., 360.); - CLLocationDistance altitude = MGLAltitudeForZoomLevel(*camera.zoom, pitch, 0, self.frame.size); - self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(*camera.center) + + double pitch = camera.pitch ? *camera.pitch : 0.0; + double bearing = camera.bearing ? *camera.bearing : 0.0; + double zoom = camera.zoom ? *camera.zoom : 0.0; + mbgl::LatLng center = camera.center ? *camera.center : mbgl::LatLng(); + + CLLocationDirection heading = mbgl::util::wrap(bearing, 0., 360.); + CLLocationDistance altitude = MGLAltitudeForZoomLevel(zoom, pitch, 0, self.frame.size); + self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(center) altitude:altitude pitch:pitch heading:heading]; @@ -2560,11 +2695,13 @@ public: } } -- (void)setPrefetchesTiles:(BOOL)prefetchesTiles{ +- (void)setPrefetchesTiles:(BOOL)prefetchesTiles +{ _mbglMap->setPrefetchZoomDelta(prefetchesTiles ? mbgl::util::DEFAULT_PREFETCH_ZOOM_DELTA : 0); } -- (BOOL)prefetchesTiles{ +- (BOOL)prefetchesTiles +{ return _mbglMap->getPrefetchZoomDelta() > 0 ? YES : NO; } @@ -4138,6 +4275,8 @@ public: [newAnnotationContainerView addSubviews:annotationViews]; [_glView insertSubview:newAnnotationContainerView atIndex:0]; self.annotationContainerView = newAnnotationContainerView; + + self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount); } /// Initialize and return a default annotation image that depicts a round pin @@ -4311,6 +4450,8 @@ public: annotationView.annotation = nil; [annotationView removeFromSuperview]; [self.annotationContainerView.annotationViews removeObject:annotationView]; + + self.enablePresentsWithTransaction = (self.annotationContainerView.annotationViews.count > MGLPresentsWithTransactionAnnotationCount); if (annotationTag == _selectedAnnotationTag) { @@ -6686,6 +6827,20 @@ public: void onDidFinishLoadingStyle() override { [nativeView didFinishLoadingStyle]; } + + void onStyleImageMissing(const std::string& imageIdentifier) override { + NSString *imageName = [NSString stringWithUTF8String:imageIdentifier.c_str()]; + + if ([nativeView.delegate respondsToSelector:@selector(mapView:didFailToLoadImage:)]) { + UIImage *imageToLoad = [nativeView.delegate mapView:nativeView didFailToLoadImage:imageName]; + + if (imageToLoad) { + auto image = [imageToLoad mgl_styleImageWithIdentifier:imageName]; + nativeView.mbglMap.getStyle().addImage(std::move(image)); + } + + } + } mbgl::gl::ProcAddress getExtensionFunctionPointer(const char* name) override { static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h index 7e098f340d..055d4c9517 100644 --- a/platform/ios/src/MGLMapViewDelegate.h +++ b/platform/ios/src/MGLMapViewDelegate.h @@ -275,6 +275,8 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style; +- (nullable UIImage *)mapView:(MGLMapView *)mapView didFailToLoadImage:(NSString *)imageName; + #pragma mark Tracking User Location /** diff --git a/platform/ios/src/UIColor+MGLAdditions.h b/platform/ios/src/UIColor+MGLAdditions.h index 60cfe1c58b..19702fa105 100644 --- a/platform/ios/src/UIColor+MGLAdditions.h +++ b/platform/ios/src/UIColor+MGLAdditions.h @@ -17,5 +17,6 @@ + (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components; + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components; ++ (UIColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)components; @end diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift index 2bf3dc06bd..1330281faa 100644 --- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift +++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift @@ -96,4 +96,6 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate { func mapView(_ mapView: MGLMapView, shouldChangeFrom oldCamera: MGLMapCamera, to newCamera: MGLMapCamera, reason: MGLCameraChangeReason) -> Bool { return false } func mapViewUserLocationAnchorPoint(_ mapView: MGLMapView) -> CGPoint { return CGPoint(x: 100, y: 100) } + + func mapView(_ mapView: MGLMapView, didFailToLoadImage imageName: String) -> UIImage? { return nil } } diff --git a/platform/ios/test/MGLNSDataAdditionsTests.m b/platform/ios/test/MGLNSDataAdditionsTests.m deleted file mode 100644 index 8d145be4a0..0000000000 --- a/platform/ios/test/MGLNSDataAdditionsTests.m +++ /dev/null @@ -1,48 +0,0 @@ -#import <XCTest/XCTest.h> - -#import "../../darwin/src/NSData+MGLAdditions.h" - -@interface MGLNSDataAdditionsTests : XCTestCase -@end - -@implementation MGLNSDataAdditionsTests - -- (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; -} - -- (double)safeValueBetween:(double)lowerBound and:(double)upperBound -{ - return floor([self randomBetween:lowerBound and:upperBound] * 100 ) / 100; -} - -- (double)randomBetween:(double)lowerBound and:(double)upperBound -{ - return lowerBound * drand48() + upperBound * drand48(); -} - -@end diff --git a/platform/ios/vendor/mapbox-events-ios b/platform/ios/vendor/mapbox-events-ios -Subproject d79e62581df5f51a0064dd2f78972c489c71d41 +Subproject 67d59dbe10f232dfeb3a1604c6696c6619abe88 diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 6d4715e451..4405e0583f 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -104,13 +104,8 @@ endmacro() macro(mbgl_filesource) - target_sources(mbgl-filesource - # File source - PRIVATE platform/default/src/mbgl/storage/http_file_source.cpp - - # Database - PRIVATE platform/default/src/mbgl/storage/sqlite3.cpp - ) + # Modify platform/linux/filesource-files.json to change the source files for this target. + target_sources_from_file(mbgl-filesource PRIVATE platform/linux/filesource-files.json) # We're not referencing any cURL symbols since we're dynamically loading it. However, we want to # link the library anyway since we're definitely going to load it on startup anyway. diff --git a/platform/linux/filesource-files.json b/platform/linux/filesource-files.json new file mode 100644 index 0000000000..448f5f8613 --- /dev/null +++ b/platform/linux/filesource-files.json @@ -0,0 +1,10 @@ +{ + "//": "This file can be edited manually and is the canonical source.", + "sources": [ + "platform/default/src/mbgl/storage/file_source.cpp", + "platform/default/src/mbgl/storage/http_file_source.cpp", + "platform/default/src/mbgl/storage/sqlite3.cpp" + ], + "public_headers": {}, + "private_headers": {} +} diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 2542f57d95..ebfb3f335a 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -10,6 +10,12 @@ * Added `MGLNetworkConfiguration` class to customize the SDK's `NSURLSessionConfiguration` object. ([#11447](https://github.com/mapbox/mapbox-gl-native/pull/13886)) * Fixed an issue that caused `MGL_FUNCTION` to ignore multiple formatting parameters when passed a `format` function as parameter. ([#14064](https://github.com/mapbox/mapbox-gl-native/pull/14064)) * Added `mgl_attributed:` expression operator, which concatenate `MGLAttributedExpression` objects for specifying rich text in the `MGLSymbolStyleLayer.text` property. ([#14094](https://github.com/mapbox/mapbox-gl-native/pull/14094)) +* Fixed an issue that caused conditional expressions to crash when passed nested conditional expressions as parameters. ([#14181](https://github.com/mapbox/mapbox-gl-native/pull/14181)) +* Added `-[MGLMapViewDelegate mapView:didFailToLoadImage:]` to load missing symbol icons in the style if they are not found. ([#14302](https://github.com/mapbox/mapbox-gl-native/pull/14302)) + +### Offline + +* Fixed a bug that caused offline packs created prior to v0.7.0 (introduced in [#11055](https://github.com/mapbox/mapbox-gl-native/pull/11055)) to be marked as `MGLOfflinePackStateInactive`. ([#14188](https://github.com/mapbox/mapbox-gl-native/pull/14188)) ### Annotations @@ -19,6 +25,7 @@ ### Packaging * Added Czech and Galician localizations. ([#13782](https://github.com/mapbox/mapbox-gl-native/pull/13782), [#14095](https://github.com/mapbox/mapbox-gl-native/pull/14095)) +* Added support for building with Xcode 10.2 / iOS SDK 12.2. ([#14241](https://github.com/mapbox/mapbox-gl-native/pull/14241)) ## 0.13.0 - December 20, 2018 diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md index 038ddf1f93..5a81eb3593 100644 --- a/platform/macos/docs/guides/For Style Authors.md +++ b/platform/macos/docs/guides/For Style Authors.md @@ -411,5 +411,16 @@ In style JSON | In the format string `["any", f0, …, fn]` | `p0 OR … OR pn` `["none", f0, …, fn]` | `NOT (p0 OR … OR pn)` +## Specifying the text format + +The following format attributes are defined as `NSString` constans that you +can use to update the formatting of `MGLSymbolStyleLayer.text` property. + +In style JSON | In Objective-C | In Swift +--------------|-----------------------|--------- +`text-font` | `MGLFontNamesAttribute` | `.fontNamesAttribute` +`font-scale` | `MGLFontScaleAttribute` | `.fontScaleAttribute` +`text-color` | `MGLFontColorAttribute` | `.fontColorAttribute` + See the “[Predicates and Expressions](predicates-and-expressions.html)” guide for a full description of the supported operators and operand types. diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 5d5a94c78a..57c4f198f0 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -2008,6 +2008,7 @@ GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 911d254889..0fdecd6cc8 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -36,8 +36,8 @@ #import <mbgl/renderer/renderer.hpp> #import <mbgl/renderer/renderer_backend.hpp> #import <mbgl/renderer/backend_scope.hpp> -#import <mbgl/storage/default_file_source.hpp> #import <mbgl/storage/network_status.hpp> +#import <mbgl/storage/resource_options.hpp> #import <mbgl/math/wrap.hpp> #import <mbgl/util/constants.hpp> #import <mbgl/util/chrono.hpp> @@ -292,10 +292,17 @@ public: mbgl::MapOptions mapOptions; mapOptions.withMapMode(mbgl::MapMode::Continuous) + .withSize(self.size) + .withPixelRatio(config.scaleFactor) .withConstrainMode(mbgl::ConstrainMode::None) .withViewportMode(mbgl::ViewportMode::Default) .withCrossSourceCollisions(enableCrossSourceCollisions); - _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, self.size, config.scaleFactor, *config.fileSource, *_mbglThreadPool, mapOptions); + + mbgl::ResourceOptions resourceOptions; + resourceOptions.withCachePath([[MGLOfflineStorage sharedOfflineStorage] mbglCachePath]) + .withAssetPath([NSBundle mainBundle].resourceURL.path.UTF8String); + + _mbglMap = new mbgl::Map(*_rendererFrontend, *_mbglView, *_mbglThreadPool, mapOptions, resourceOptions); // Install the OpenGL layer. Interface Builder’s synchronous drawing means // we can’t display a map, so don’t even bother to have a map layer. @@ -690,7 +697,7 @@ public: self.dormant = NO; } - if (window && _mbglMap->getConstrainMode() == mbgl::ConstrainMode::None) { + if (window && _mbglMap->getMapOptions().constrainMode() == mbgl::ConstrainMode::None) { _mbglMap->setConstrainMode(mbgl::ConstrainMode::HeightOnly); } diff --git a/platform/macos/src/NSColor+MGLAdditions.h b/platform/macos/src/NSColor+MGLAdditions.h index 21c939fec6..a3c5aba63f 100644 --- a/platform/macos/src/NSColor+MGLAdditions.h +++ b/platform/macos/src/NSColor+MGLAdditions.h @@ -23,5 +23,6 @@ + (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components; + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components; ++ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions; @end diff --git a/platform/macos/src/NSColor+MGLAdditions.mm b/platform/macos/src/NSColor+MGLAdditions.mm index c73c1a41b7..ea7d99f66d 100644 --- a/platform/macos/src/NSColor+MGLAdditions.mm +++ b/platform/macos/src/NSColor+MGLAdditions.mm @@ -37,7 +37,7 @@ @implementation NSExpression (MGLColorAdditions) + (NSExpression *)mgl_expressionForRGBComponents:(NSArray<NSExpression *> *)components { - if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) { + if (NSColor *color = [self mgl_colorWithRGBComponents:components]) { return [NSExpression expressionForConstantValue:color]; } @@ -49,7 +49,7 @@ } + (NSExpression *)mgl_expressionForRGBAComponents:(NSArray<NSExpression *> *)components { - if (NSColor *color = [self mgl_colorWithComponentExpressions:components]) { + if (NSColor *color = [self mgl_colorWithRGBComponents:components]) { return [NSExpression expressionForConstantValue:color]; } @@ -62,7 +62,7 @@ /** Returns a color object corresponding to the given component expressions. */ -+ (NSColor *)mgl_colorWithComponentExpressions:(NSArray<NSExpression *> *)componentExpressions { ++ (NSColor *)mgl_colorWithRGBComponents:(NSArray<NSExpression *> *)componentExpressions { // Map the component expressions to constant components. If any component is // a non-constant expression, the components cannot be converted into a // constant color value. diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 0d69e606c1..291dea6bb7 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -20,15 +20,25 @@ #include <mbgl/style/layers/raster_layer.hpp> #include <mbgl/style/layers/symbol_layer.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> #include <mbgl/style/light.hpp> +#include <mbgl/map/map.hpp> #include <mbgl/map/map_observer.hpp> #include <mbgl/util/exception.hpp> #include <mbgl/util/premultiply.hpp> #include <unistd.h> +namespace mbgl { + +std::shared_ptr<FileSource> FileSource::createPlatformFileSource(const ResourceOptions& options) { + return std::make_shared<node_mbgl::NodeFileSource>(reinterpret_cast<node_mbgl::NodeMap*>(options.platformContext())); +} + +} // namespace mbgl + namespace node_mbgl { struct NodeMap::RenderOptions { @@ -621,13 +631,12 @@ void NodeMap::cancel() { }); frontend = std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size{ 256, 256 }, pixelRatio, threadpool); - mbgl::MapOptions options; - options.withMapMode(mode) - .withConstrainMode(mbgl::ConstrainMode::HeightOnly) - .withViewportMode(mbgl::ViewportMode::Default) - .withCrossSourceCollisions(crossSourceCollisions); - map = std::make_unique<mbgl::Map>(*frontend, mapObserver, frontend->getSize(), pixelRatio, - fileSource, threadpool, options); + map = std::make_unique<mbgl::Map>(*frontend, mapObserver, threadpool, + mbgl::MapOptions().withSize(frontend->getSize()) + .withPixelRatio(pixelRatio) + .withMapMode(mode) + .withCrossSourceCollisions(crossSourceCollisions), + mbgl::ResourceOptions().withPlatformContext(reinterpret_cast<void*>(this))); // FIXME: Reload the style after recreating the map. We need to find // a better way of canceling an ongoing rendering on the core level @@ -1205,20 +1214,14 @@ NodeMap::NodeMap(v8::Local<v8::Object> options) : true; }()) , mapObserver(NodeMapObserver()) - , fileSource(this) , frontend(std::make_unique<mbgl::HeadlessFrontend>(mbgl::Size { 256, 256 }, pixelRatio, threadpool)) - , map(std::make_unique<mbgl::Map>(*frontend, - mapObserver, - frontend->getSize(), - pixelRatio, - fileSource, - threadpool, - mbgl::MapOptions().withMapMode(mode) - .withConstrainMode(mbgl::ConstrainMode::HeightOnly) - .withViewportMode(mbgl::ViewportMode::Default) - .withCrossSourceCollisions(crossSourceCollisions))), - async(new uv_async_t) { - + , map(std::make_unique<mbgl::Map>(*frontend, mapObserver, threadpool, + mbgl::MapOptions().withSize(frontend->getSize()) + .withPixelRatio(pixelRatio) + .withMapMode(mode) + .withCrossSourceCollisions(crossSourceCollisions), + mbgl::ResourceOptions().withPlatformContext(reinterpret_cast<void*>(this)))) + , async(new uv_async_t) { async->data = this; uv_async_init(uv_default_loop(), async, [](uv_async_t* h) { reinterpret_cast<NodeMap *>(h->data)->renderFinished(); @@ -1232,8 +1235,6 @@ NodeMap::~NodeMap() { if (map) release(); } -NodeFileSource::NodeFileSource(NodeMap* nodeMap_) : nodeMap(nodeMap_) {} - std::unique_ptr<mbgl::AsyncRequest> NodeFileSource::request(const mbgl::Resource& resource, mbgl::FileSource::Callback callback_) { assert(nodeMap); @@ -1248,15 +1249,15 @@ std::unique_ptr<mbgl::AsyncRequest> NodeFileSource::request(const mbgl::Resource Nan::New<v8::External>(&callback_) }; - auto instance = Nan::NewInstance(Nan::New(NodeRequest::constructor), 2, argv).ToLocalChecked(); + auto instance = Nan::NewInstance(Nan::New(node_mbgl::NodeRequest::constructor), 2, argv).ToLocalChecked(); Nan::Set(instance, Nan::New("url").ToLocalChecked(), Nan::New(resource.url).ToLocalChecked()); Nan::Set(instance, Nan::New("kind").ToLocalChecked(), Nan::New<v8::Integer>(resource.kind)); - auto request = Nan::ObjectWrap::Unwrap<NodeRequest>(instance); + auto request = Nan::ObjectWrap::Unwrap<node_mbgl::NodeRequest>(instance); request->Execute(); - return std::make_unique<NodeRequest::NodeAsyncRequest>(request); + return std::make_unique<node_mbgl::NodeRequest::NodeAsyncRequest>(request); } } // namespace node_mbgl diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 9e3eb1ad12..65664b34bb 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -15,26 +15,13 @@ #pragma GCC diagnostic pop namespace mbgl { -class Map; class HeadlessFrontend; } // namespace mbgl namespace node_mbgl { -class NodeMapObserver : public mbgl::MapObserver { - void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) override; -}; - -class NodeMap; - -class NodeFileSource : public mbgl::FileSource { -public: - NodeFileSource(NodeMap*); - - std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback) final; - -private: - NodeMap* nodeMap; +struct NodeMapObserver : public mbgl::MapObserver { + void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) final; }; class RenderRequest; @@ -94,7 +81,6 @@ public: bool crossSourceCollisions; NodeThreadPool threadpool; NodeMapObserver mapObserver; - NodeFileSource fileSource; std::unique_ptr<mbgl::HeadlessFrontend> frontend; std::unique_ptr<mbgl::Map> map; @@ -108,4 +94,10 @@ public: bool loaded = false; }; +struct NodeFileSource : public mbgl::FileSource { + NodeFileSource(NodeMap* nodeMap_) : nodeMap(nodeMap_) {} + std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback) final; + NodeMap* nodeMap; +}; + } // namespace node_mbgl diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index d0becfc58a..060f4935a6 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -149,24 +149,9 @@ "render-tests/symbol-sort-key/text-expression": "https://github.com/mapbox/mapbox-gl-native/issues/14028", "render-tests/symbol-sort-key/text-placement": "https://github.com/mapbox/mapbox-gl-native/issues/14028", "render-tests/fill-opacity/opaque-fill-over-symbol-layer": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/7612", - "render-tests/text-radial-offset/basic": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/all-anchors-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/all-anchors": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/icon-image-all-anchors": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/icon-image": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/no-animate-zoom": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/pitched-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/pitched-rotated-debug": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/pitched-with-map": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/pitched": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/remember-last-placement": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/rotated-offset": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/rotated-with-map": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/rotated": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/single-justification": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/single-line": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-variable-anchor/top-bottom-left-right": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", - "render-tests/text-justify/auto": "skip - port of https://github.com/mapbox/mapbox-gl-js/pull/7596", + "render-tests/text-variable-anchor/pitched-rotated-debug": "https://github.com/mapbox/mapbox-gl-native/issues/14211", + "render-tests/text-variable-anchor/rotated-offset": "https://github.com/mapbox/mapbox-gl-native/issues/14211", + "render-tests/text-variable-anchor/remember-last-placement": "skip - fails on gl-native, as symbol index is not functional at static map mode - needs issue", "render-tests/geojson/clustered-properties": "https://github.com/mapbox/mapbox-gl-native/issues/14043", "render-tests/remove-feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413", "render-tests/remove-feature-state/data-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12413", diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 14f09007ac..911af25bc4 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -50,6 +50,7 @@ set(MBGL_QT_CORE_FILES set(MBGL_QT_FILESOURCE_FILES # File source + PRIVATE platform/default/src/mbgl/storage/file_source.cpp PRIVATE platform/qt/src/http_file_source.cpp PRIVATE platform/qt/src/http_file_source.hpp PRIVATE platform/qt/src/http_request.cpp diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index b05c82a783..4f79525257 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -10,6 +10,7 @@ #include <mbgl/annotation/annotation.hpp> #include <mbgl/map/camera.hpp> #include <mbgl/map/map.hpp> +#include <mbgl/map/map_options.hpp> #include <mbgl/math/log2.hpp> #include <mbgl/math/minmax.hpp> #include <mbgl/style/style.hpp> @@ -33,7 +34,9 @@ #include <mbgl/style/image.hpp> #include <mbgl/renderer/renderer.hpp> #include <mbgl/renderer/backend_scope.hpp> +#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/network_status.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/util/color.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/geo.hpp> @@ -91,49 +94,6 @@ namespace { QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop; -std::shared_ptr<mbgl::DefaultFileSource> sharedDefaultFileSource(const QMapboxGLSettings &settings) { - static std::mutex mutex; - static std::unordered_map<std::string, std::weak_ptr<mbgl::DefaultFileSource>> fileSources; - - const std::string cachePath = settings.cacheDatabasePath().toStdString(); - const std::string accessToken = settings.accessToken().toStdString(); - const std::string apiBaseUrl = settings.apiBaseUrl().toStdString(); - - std::lock_guard<std::mutex> lock(mutex); - - // Purge entries no longer in use. - for (auto it = fileSources.begin(); it != fileSources.end();) { - if (it->second.expired()) { - it = fileSources.erase(it); - } else { - ++it; - } - } - - const auto key = cachePath + "|" + accessToken + "|" + apiBaseUrl; - - // Return an existing FileSource if available. - auto sharedFileSource = fileSources.find(key); - if (sharedFileSource != fileSources.end()) { - auto lockedSharedFileSource = sharedFileSource->second.lock(); - if (lockedSharedFileSource) { - return lockedSharedFileSource; - } - } - - // New path, create a new FileSource. - auto newFileSource = std::make_shared<mbgl::DefaultFileSource>( - cachePath, settings.assetPath().toStdString(), settings.cacheDatabaseMaximumSize()); - - // Setup the FileSource - newFileSource->setAccessToken(accessToken); - newFileSource->setAPIBaseURL(apiBaseUrl); - - fileSources[key] = newFileSource; - - return newFileSource; -} - // Conversion helper functions. mbgl::Size sanitizedSize(const QSize& size) { @@ -907,7 +867,7 @@ void QMapboxGL::pitchBy(double pitch_) */ QMapboxGL::NorthOrientation QMapboxGL::northOrientation() const { - return static_cast<QMapboxGL::NorthOrientation>(d_ptr->mapObj->getNorthOrientation()); + return static_cast<QMapboxGL::NorthOrientation>(d_ptr->mapObj->getMapOptions().northOrientation()); } /*! @@ -1167,7 +1127,7 @@ void QMapboxGL::resize(const QSize& size_) { auto size = sanitizedSize(size_); - if (d_ptr->mapObj->getSize() == size) + if (d_ptr->mapObj->getMapOptions().size() == size) return; d_ptr->mapObj->setSize(size); @@ -1745,22 +1705,31 @@ void QMapboxGL::connectionEstablished() \a copyrightsHtml is a string with a HTML snippet. */ +mbgl::MapOptions mapOptionsFromQMapboxGLSettings(const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio) { + return std::move(mbgl::MapOptions() + .withSize(sanitizedSize(size)) + .withPixelRatio(pixelRatio) + .withMapMode(static_cast<mbgl::MapMode>(settings.mapMode())) + .withConstrainMode(static_cast<mbgl::ConstrainMode>(settings.constrainMode())) + .withViewportMode(static_cast<mbgl::ViewportMode>(settings.viewportMode()))); +} + +mbgl::ResourceOptions resourceOptionsFromQMapboxGLSettings(const QMapboxGLSettings &settings) { + return std::move(mbgl::ResourceOptions() + .withAccessToken(settings.accessToken().toStdString()) + .withAssetPath(settings.assetPath().toStdString()) + .withBaseURL(settings.apiBaseUrl().toStdString()) + .withCachePath(settings.cacheDatabasePath().toStdString()) + .withMaximumCacheSize(settings.cacheDatabaseMaximumSize())); +} + QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size, qreal pixelRatio_) : QObject(q) - , m_fileSourceObj(sharedDefaultFileSource(settings)) , m_threadPool(mbgl::sharedThreadPool()) , m_mode(settings.contextMode()) , m_pixelRatio(pixelRatio_) , m_localFontFamily(settings.localFontFamily()) { - if (settings.resourceTransform()) { - m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(), - [callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string { - return callback(std::move(url_)); - }); - m_fileSourceObj->setResourceTransform(m_resourceTransform->self()); - } - // Setup MapObserver m_mapObserver = std::make_unique<QMapboxGLMapObserver>(this); @@ -1770,18 +1739,21 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin connect(m_mapObserver.get(), SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)), q, SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString))); connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString))); - mbgl::MapOptions options; - options.withMapMode(static_cast<mbgl::MapMode>(settings.mapMode())) - .withConstrainMode(static_cast<mbgl::ConstrainMode>(settings.constrainMode())) - .withViewportMode(static_cast<mbgl::ViewportMode>(settings.viewportMode())); - - // Setup the Map object - mapObj = std::make_unique<mbgl::Map>( - *this, // RendererFrontend - *m_mapObserver, - sanitizedSize(size), - m_pixelRatio, *m_fileSourceObj, *m_threadPool, - options); + auto resourceOptions = resourceOptionsFromQMapboxGLSettings(settings); + + // Setup the Map object. + mapObj = std::make_unique<mbgl::Map>(*this, *m_mapObserver, *m_threadPool, + mapOptionsFromQMapboxGLSettings(settings, size, m_pixelRatio), + resourceOptions); + + if (settings.resourceTransform()) { + m_resourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::Scheduler::GetCurrent(), + [callback = settings.resourceTransform()] (mbgl::Resource::Kind, const std::string &&url_) -> std::string { + return callback(std::move(url_)); + }); + auto fs = mbgl::FileSource::getSharedFileSource(resourceOptions); + std::static_pointer_cast<mbgl::DefaultFileSource>(fs)->setResourceTransform(m_resourceTransform->self()); + } // Needs to be Queued to give time to discard redundant draw calls via the `renderQueued` flag. connect(this, SIGNAL(needsRendering()), q, SIGNAL(needsRendering()), Qt::QueuedConnection); diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 7157df0aba..6a5b5ce04f 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -7,7 +7,6 @@ #include <mbgl/actor/actor.hpp> #include <mbgl/map/map.hpp> #include <mbgl/renderer/renderer_frontend.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/resource_transform.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/util/geo.hpp> @@ -57,7 +56,6 @@ private: std::shared_ptr<mbgl::UpdateParameters> m_updateParameters; std::unique_ptr<QMapboxGLMapObserver> m_mapObserver; - std::shared_ptr<mbgl::DefaultFileSource> m_fileSourceObj; std::shared_ptr<mbgl::ThreadPool> m_threadPool; std::unique_ptr<QMapboxGLMapRenderer> m_mapRenderer; std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform>> m_resourceTransform; diff --git a/scripts/clang-tools.sh b/scripts/clang-tools.sh index bdda4544b9..1e73951176 100755 --- a/scripts/clang-tools.sh +++ b/scripts/clang-tools.sh @@ -33,7 +33,7 @@ function run_clang_tidy() { } function run_clang_tidy_diff() { - OUTPUT=$(git diff origin/master --src-prefix=${CDUP} --dst-prefix=${CDUP} | \ + OUTPUT=$(git diff origin/$2 --src-prefix=${CDUP} --dst-prefix=${CDUP} | \ ${CLANG_TIDY_PREFIX}/share/clang-tidy-diff.py \ -clang-tidy-binary ${CLANG_TIDY} \ 2>/dev/null) @@ -45,7 +45,7 @@ function run_clang_tidy_diff() { function run_clang_format() { echo "Running clang-format on $0..." - DIFF_FILES=$(git diff origin/master --name-only *cpp) + DIFF_FILES=$(git diff origin/$2 --name-only *cpp) echo "${DIFF_FILES}" | xargs -I{} -P ${JOBS} bash -c 'run_clang_format' {} ${CLANG_FORMAT} -i ${CDUP}/$0 || exit 1 } @@ -54,7 +54,7 @@ export -f run_clang_tidy run_clang_tidy_diff run_clang_format echo "Running Clang checks... (this might take a while)" -if [[ -n $2 ]] && [[ $2 == "--diff" ]]; then +if [[ -n $3 ]] && [[ $3 == "--diff" ]]; then run_clang_tidy_diff $@ # XXX disabled until we run clang-format over the entire codebase. #run_clang_format $@ diff --git a/scripts/code-coverage.sh b/scripts/code-coverage.sh index d6866f61b8..cb99bd9646 100755 --- a/scripts/code-coverage.sh +++ b/scripts/code-coverage.sh @@ -4,7 +4,7 @@ set -e set -o pipefail # -# This script takes three values: $1 should be a decimal value reflecting the +# This script takes three values: $1 should be a decimal value reflecting the # percentage of lines covered, with a maximum value of 100.0, $2 is # the platform the percentage pertains to (iOS or Android), and $3 is the # test scheme being run (on iOS, this is currently CI). @@ -17,19 +17,22 @@ if [[ ! $2 = "iOS" && ! $2 = "Android" ]]; then exit 1 fi -# Create a formatted JSON file that contains the current coverage. +circle_sha="" +if [[ $CIRCLE_SHA1 ]]; then + circle_sha="$CIRCLE_SHA1" +fi +# Create a formatted JSON file that contains the current coverage. -current_date=$(TZ=UTC date +"%Y-%m-%d") +current_date=$(TZ=UTC date +"%FT%T%z") file_name=$2_coverage.json cat <<EOF > $file_name - {"code_coverage":$1,"platform":"$2","sdk":"Maps","scheme":"$3","created_at":"$current_date"} +{"code_coverage":$1,"platform":"$2","sdk":"Maps","scheme":"$3","created_at":"$current_date","sha":"$circle_sha"} EOF gzip -f $file_name -if [ -z `which aws` ]; then - brew install awscli +if [ -z `which aws` ]; then + brew install awscli fi aws s3 cp $file_name.gz s3://mapbox-loading-dock/raw/mobile.codecoverage/$current_date/ echo $ - diff --git a/scripts/generate-file-lists.js b/scripts/generate-file-lists.js index 37e4dbc20b..760a01d87c 100755 --- a/scripts/generate-file-lists.js +++ b/scripts/generate-file-lists.js @@ -124,6 +124,7 @@ generateXcodeSourceList('platform/macos/macos.xcodeproj', 'dynamic', 'sdk'); generateXcodeSourceList('platform/ios/ios.xcodeproj', 'dynamic', 'sdk'); const vendorRegex = /^(?:(?:src|include)\/)?(?:(.+)\/)?[^\/]+$/ +generateFileList('vendor/args-files.json', 'vendor/args', vendorRegex, [ "args.hxx" ]); generateFileList('vendor/boost-files.json', 'vendor/boost', vendorRegex, [ "include/**/*.hpp", "include/**/*.h" ]); generateFileList('vendor/cheap-ruler-cpp-files.json', 'vendor/cheap-ruler-cpp', vendorRegex, [ "include/**/*.hpp" ]); generateFileList('vendor/earcut.hpp-files.json', 'vendor/earcut.hpp', vendorRegex, [ "include/**/*.hpp" ]); diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js index 59544d0b34..fc9088fd21 100755 --- a/scripts/generate-shaders.js +++ b/scripts/generate-shaders.js @@ -5,6 +5,7 @@ require('flow-remove-types/register'); const path = require('path'); const outputPath = 'src/mbgl/programs/gl'; const zlib = require('zlib'); +const crypto = require('crypto'); var shaders = require('../mapbox-gl-js/src/shaders'); @@ -23,18 +24,28 @@ function basicMinify(src) { } for (const key in shaders) { + // Rename a_*_t uniforms to u_*_t. This is a workaround until we can use + // https://github.com/mapbox/mapbox-gl-js/pull/8055, which is blocked by + // https://github.com/mapbox/mapbox-gl-native/issues/13984 + shaders[key].vertexSource = shaders[key].vertexSource.replace(/\ba_(\w+)_t\b/mg, 'u_$1_t'); + + const hash = crypto.createHash('sha1'); + const vertex = concatenated.length; - concatenated += basicMinify(shaders[key].vertexSource); - concatenated += '\n\0'; + const vertexSource = basicMinify(shaders[key].vertexSource) + '\n\0'; + hash.update(vertexSource); + concatenated += vertexSource; const fragment = concatenated.length; - concatenated += basicMinify(shaders[key].fragmentSource); - concatenated += '\n\0'; + const fragmentSource = basicMinify(shaders[key].fragmentSource) + '\n\0'; + hash.update(fragmentSource); + concatenated += fragmentSource; offsets[key] = { vertex, fragment, originalKey: key, + hash: hash.digest('hex').substring(0, 16).match(/.{1,2}/g).map(n => `0x${n}`).join(', '), shaderName: key.replace(/[A-Z]+/g, (match) => `_${match.toLowerCase()}`), ShaderName: key.replace(/^[a-z]/g, (match) => match.toUpperCase()) }; @@ -44,6 +55,7 @@ for (const key in shaders) { offsets.symbolSDFIcon = { vertex: offsets.symbolSDF.vertex, fragment: offsets.symbolSDF.fragment, + hash: offsets.symbolSDF.hash, originalKey: 'symbolSDF', shaderName: 'symbol_sdf_icon', ShaderName: 'SymbolSDFIcon', @@ -52,6 +64,7 @@ offsets.symbolSDFIcon = { offsets.symbolSDFText = { vertex: offsets.symbolSDF.vertex, fragment: offsets.symbolSDF.fragment, + hash: offsets.symbolSDF.hash, originalKey: 'symbolSDF', shaderName: 'symbol_sdf_text', ShaderName: 'SymbolSDFText', @@ -66,10 +79,6 @@ const compressed = zlib.deflateSync(concatenated, {level: zlib.Z_BEST_COMPRESSIO .join(',\n ') .trim(); -function sourceOffset(key, type) { - return `programs::gl::shaderSource() + ${offsets[key][type]}` -} - writeIfModified(path.join(outputPath, 'shader_source.hpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #pragma once @@ -80,6 +89,9 @@ namespace gl { const char* shaderSource(); +template <typename> +struct ShaderSource; + } // namespace gl } // namespace programs } // namespace mbgl @@ -114,29 +126,15 @@ writeIfModified(path.join(outputPath, 'preludes.hpp'), `// NOTE: DO NOT CHANGE T #pragma once -namespace mbgl { -namespace programs { -namespace gl { - -extern const char* vertexShaderPrelude; -extern const char* fragmentShaderPrelude; - -} // namespace gl -} // namespace programs -} // namespace mbgl -`); - -writeIfModified(path.join(outputPath, 'preludes.cpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. - -#include <mbgl/programs/gl/preludes.hpp> -#include <mbgl/programs/gl/shader_source.hpp> +#include <cstdint> namespace mbgl { namespace programs { namespace gl { -const char* vertexShaderPrelude = ${sourceOffset('prelude', 'vertex')}; -const char* fragmentShaderPrelude = ${sourceOffset('prelude', 'fragment')}; +constexpr const uint8_t preludeHash[8] = { ${offsets['prelude'].hash} }; +constexpr const auto vertexPreludeOffset = ${offsets['prelude'].vertex}; +constexpr const auto fragmentPreludeOffset = ${offsets['prelude'].fragment}; } // namespace gl } // namespace programs @@ -152,18 +150,37 @@ for (const key in offsets) { writeIfModified(path.join(outputPath, `${shaderName}.cpp`), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/${shaderName}_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<${ShaderName}Program> { + static constexpr const char* name = "${shaderName}"; + static constexpr const uint8_t hash[8] = { ${offsets[key].hash} }; + static constexpr const auto vertexOffset = ${offsets[key].vertex}; + static constexpr const auto fragmentOffset = ${offsets[key].fragment}; +}; + +constexpr const char* ShaderSource<${ShaderName}Program>::name; +constexpr const uint8_t ShaderSource<${ShaderName}Program>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<${ShaderName}Program>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<${ShaderName}Program>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "${shaderName}", - ${sourceOffset(key, 'vertex')}, ${sourceOffset(key, 'fragment')}); + return std::make_unique<gl::Program<${ShaderName}Program>>(programParameters); } } // namespace gfx diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index ae25a856a8..5145755cec 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -72,7 +72,7 @@ global.evaluatedType = function (property) { if (property.length) { return `std::array<${evaluatedType({type: property.value})}, ${property.length}>`; } else { - return `std::vector<${evaluatedType({type: property.value})}>`; + return `std::vector<${evaluatedType({type: property.value, name: property.name})}>`; } default: throw new Error(`unknown type for ${property.name}`) } @@ -99,7 +99,7 @@ function attributeUniformType(property, type) { [ property.name.replace(type + '-', '').replace(/-/g, '_') ]; return names.map(name => { - return `attributes::a_${name}, uniforms::u_${name}` + return `attributes::${name}, uniforms::${name}` }).join(', '); } @@ -153,7 +153,11 @@ global.defaultValue = function (property) { switch (property.type) { case 'number': + if (property.default === undefined) { + return 0; + } else { return property.default; + } case 'formatted': case 'string': return JSON.stringify(property.default || ""); diff --git a/scripts/publish_core_codecoverage.js b/scripts/publish_core_codecoverage.js new file mode 100755 index 0000000000..43de662a13 --- /dev/null +++ b/scripts/publish_core_codecoverage.js @@ -0,0 +1,170 @@ +#!/usr/bin/env node + +// Script to retrieve total code coverage ratio from codecov.io +// for a given commit hash, and upload it to the S3 bucket. + +const https = require('https'); +const zlib = require('zlib'); +const AWS = require('aws-sdk'); +const {execSync} = require('child_process'); + +const args = process.argv.slice(2); +const options = { + help: false +}; + +const usage = 'usage: publish_code_coverage.js [options]\n' + +'options: \n' + +' -h, --help \n' + +' -p, --platform <Platform Name>\n' + +' -s, --sdk <Sdk Name> \n' + +' -c, --commit <Commit Hash> \n'; + +for (var i = 0; i < args.length; i++) { + var arg = args[i]; + + switch(arg) { + case '-h': + case '--help': + options.help = true; + break; + case '-s': + case '--sdk': + options.sdkName = args[i + 1]; + break; + case '-p': + case '--platform': + options.platformName = args[i + 1]; + break; + case '-c': + case '--commit': + options.commitId = args[i + 1]; + break; + } +} + +if (options.help == true) { + console.log(usage); + process.exit(0); +} + +// Commit hash +const commitHash = options.commitId ? options.commitId : process.env['CIRCLE_SHA1']; +if (!options.sdkName || !options.platformName || !commitHash) { + console.log(usage); + process.exit(0); +} + +// Commit Message +const commitMessage = execSync(`git show --pretty=format:%s -s ${commitHash}`).toString().trim(); +if (!commitMessage) { + throw new Error ('Commit message is missing'); +} + +const date = new Date().toISOString().substring(0, 19); + +process.on('uncaughtException', (err) => { + console.error(err); + process.exit(1); +}); + +// Parse the response received from codecov.io and build the +// data point that is going to be uploaded to S3 bucket. +function parseResponse(data) { + if (data && data.commit) { + if (!data.commit.totals || !data.commit.totals.c) { + return; + } + + const source = { + code_coverage: Number(data.commit.totals.c), + platform: options.platformName, + sdk: options.sdkName, + commit: commitHash, + commit_message: commitMessage, + created_at: date + }; + + return source; + } +} + +// Upload to data source used by Mapbox internal metrics dashboards +function uploadData(data) { + return new AWS.S3({region: 'us-east-1'}).putObject({ + Body: zlib.gzipSync(JSON.stringify(data)), + Bucket: 'mapbox-loading-dock', + Key: `raw/mobile_staging.codecoverage/${date.substring(0,10)}/${options.sdkName}-coverage-${commitHash}.json.gz`, + CacheControl: 'max-age=300', + ContentEncoding: 'gzip', + ContentType: 'application/json' + }).promise(); +} + +// Attempt to retrieve code coverage report from codecov.io +// for a given commit hash. +function httpRequest() { + const options = { + hostname: 'codecov.io', + port: 443, + path: '/api/gh/mapbox/mapbox-gl-native/commit/' + commitHash, + method: 'GET' + }; + + return new Promise((resolve, reject) => { + setTimeout(function() { + const req = https.request(options, (res) => { + var body = []; + res.on('data', (chunk) => { + body.push(chunk); + }).on('error', (error) => { + reject(error); + }).on('end', () => { + if (res.statusCode < 200 || res.statusCode >= 300) { + return reject(new Error('Failed to fetch coverage report from codecov.io. StatusCode=' + res.statusCode)); + } + + try { + body = JSON.parse(Buffer.concat(body).toString()); + resolve(body); + } catch(e) { + reject(e); + } + }); + }); + + // Reject on error + req.on('error', (err) => { + reject(err); + }); + + req.end(); + }, 30000); + }); +} + +var errResponse = false; +const publishWithRetry = (maxRetries) => { + httpRequest().then((body) => { + const dataSource = parseResponse(body); + if (dataSource) { + return uploadData(dataSource); + } else { + errResponse = true; + throw new Error('Failed to parse coverage report received from codecov.io.'); + } + }).then(data => { + console.log('Successfully uploaded code coverage metrics to S3'); + }).catch(err => { + if (maxRetries > 1 && errResponse) { + console.log('Invalid coverage report received. Trying to retrieve again.'); + errResponse = false; + return publishWithRetry(maxRetries - 1); + } + + console.error('Failed to upload code coverage metrics to S3: ' + err.message); + }); +}; + +// Fetch and publish code coverage report +publishWithRetry(5); diff --git a/scripts/publish_github_stats.js b/scripts/publish_github_stats.js new file mode 100755 index 0000000000..f79a5082d0 --- /dev/null +++ b/scripts/publish_github_stats.js @@ -0,0 +1,147 @@ +#!/usr/bin/env node + +const assert = require('assert'); +const jwt = require('jsonwebtoken'); +const github = require('@octokit/rest')(); +const zlib = require('zlib'); +const AWS = require('aws-sdk'); + +const SIZE_CHECK_APP_ID = 14028; +const SIZE_CHECK_APP_INSTALLATION_ID = 229425; + +// Error handling + +process.on('unhandledRejection', error => { + console.log(error); + process.exit(1) +}); + +// Github authorization + +const pk = process.env['SIZE_CHECK_APP_PRIVATE_KEY']; +if (!pk) { + console.log('Fork PR; not publishing size.'); + process.exit(0); +} + +const key = Buffer.from(pk, 'base64').toString('binary'); +const payload = { + exp: Math.floor(Date.now() / 1000) + 60, + iat: Math.floor(Date.now() / 1000), + iss: SIZE_CHECK_APP_ID +}; + +const token = jwt.sign(payload, key, {algorithm: 'RS256'}); +github.authenticate({type: 'app', token}); + +// Metrics: Github statistics +let openIssuesTotal = 0; +let openIssuesTotalFromNonMembers = 0; +let openIssuesTotalCore = 0; +let openIssuesTotalAndroid = 0; +let openIssuesTotalIOS = 0; +let openIssuesTotalGLJSParity = 0; +let openPullRequestsTotal = 0; +let openPullRequestsTotalFromNonMembers = 0; +let openPullRequestsSinceLastMonth = 0; +let openPullRequestsSinceLastMonthFromNonMembers = 0; + +function collectMetricsFromIssues(issues) { + const oneMonthAgo = function() { let date = new Date(); date.setMonth(date.getMonth() - 1); return date; }(); + + // Metrics + issues.data.forEach(function (issue) { + const issueCreatedAt = new Date(issue.created_at); + const isMapboxAuthor = issue.author_association === "MEMBER"; + + if (issue.pull_request) { + openPullRequestsTotal++; + if (!isMapboxAuthor) { + openPullRequestsTotalFromNonMembers++; + } + if (issueCreatedAt >= oneMonthAgo) { + openPullRequestsSinceLastMonth++; + if (!isMapboxAuthor) { + openPullRequestsSinceLastMonthFromNonMembers++; + } + } + } else { + openIssuesTotal++; + if (!isMapboxAuthor) { + openIssuesTotalFromNonMembers++; + } + issue.labels.forEach(function (label) { + switch (label.name) { + case "Core": + openIssuesTotalCore++; + break; + case "Android": + openIssuesTotalAndroid++; + break; + case "iOS": + openIssuesTotalIOS++; + break; + case "GL JS parity": + openIssuesTotalGLJSParity++; + break; + default: + break; + } + }); + } + }); +} + +function publishMetrics() { + let metrics = { + 'created_at': new Date().toISOString().substring(0, 10), + 'open_issues_total': openIssuesTotal, + 'open_issues_total_from_non_members': openIssuesTotalFromNonMembers, + 'open_issues_total_core': openIssuesTotalCore, + 'open_issues_total_android': openIssuesTotalAndroid, + 'open_issues_total_ios': openIssuesTotalIOS, + 'open_issues_total_gl_js_parity': openIssuesTotalGLJSParity, + 'open_pull_requests_total': openPullRequestsTotal, + 'open_pull_requests_total_from_non_members': openPullRequestsTotalFromNonMembers, + 'open_pull_requests_since_last_month': openPullRequestsSinceLastMonth, + 'open_pull_requests_since_last_month_from_non_members': openPullRequestsSinceLastMonthFromNonMembers + }; + + var promise = new AWS.S3({region: 'us-east-1'}).putObject({ + Body: zlib.gzipSync(JSON.stringify(metrics)), + Bucket: 'mapbox-loading-dock', + Key: `raw/mobile_staging.github_stats/${metrics['created_at']}/METRIC.json.gz`, + CacheControl: 'max-age=300', + ContentEncoding: 'gzip', + ContentType: 'application/json' + }).promise(); + + return Promise.all([promise]).then(data => { + return console.log("Successfully uploaded Github Stats metrics to S3"); + }).catch(err => { + console.log("Error uploading Github Stats metrics to S3 " + err.message); + return err; + }); +} + +function recursiveListForRepo(query) { + assert(query); + query.then(result => { + collectMetricsFromIssues(result); + if (github.hasNextPage(result)) { + recursiveListForRepo(github.getNextPage(result)); + } else { + publishMetrics(); + } + }).catch(error => { + console.log("Error fetching the repository issues list: " + err.message); + }); +} + +github.apps.createInstallationToken({ installation_id: SIZE_CHECK_APP_INSTALLATION_ID }) + .then(({data}) => { + github.authenticate({ type: 'token', token: data.token }); + }) + .then(() => { + recursiveListForRepo(github.issues.listForRepo({ owner: 'mapbox', repo: 'mapbox-gl-native', state: 'open', per_page: 100 })); + }); diff --git a/scripts/style-spec.js b/scripts/style-spec.js index 4bbd453a86..b2686a6a77 100644 --- a/scripts/style-spec.js +++ b/scripts/style-spec.js @@ -3,9 +3,4 @@ var spec = module.exports = require('../mapbox-gl-js/src/style-spec/reference/v8 // Make temporary modifications here when Native doesn't have all features that JS has. delete spec.layout_symbol['symbol-sort-key']; delete spec.layout_symbol['symbol-z-order'].values['auto']; -spec.layout_symbol['symbol-z-order'].default = 'viewport-y'; - -delete spec.layout_symbol['text-variable-anchor']; -delete spec.layout_symbol['text-radial-offset']; -delete spec.layout_symbol['text-justify'].values['auto']; -spec.layout_symbol['text-offset'].requires.splice(1, 1); // { "!": "text-radial-offset" }
\ No newline at end of file +spec.layout_symbol['symbol-z-order'].default = 'viewport-y';
\ No newline at end of file diff --git a/src/core-files.json b/src/core-files.json index 272faaf9b6..b257666e3e 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -82,7 +82,6 @@ "src/mbgl/programs/gl/line_gradient.cpp", "src/mbgl/programs/gl/line_pattern.cpp", "src/mbgl/programs/gl/line_sdf.cpp", - "src/mbgl/programs/gl/preludes.cpp", "src/mbgl/programs/gl/raster.cpp", "src/mbgl/programs/gl/shader_source.cpp", "src/mbgl/programs/gl/shaders.cpp", @@ -144,8 +143,10 @@ "src/mbgl/sprite/sprite_loader.cpp", "src/mbgl/sprite/sprite_loader_worker.cpp", "src/mbgl/sprite/sprite_parser.cpp", + "src/mbgl/storage/file_source.cpp", "src/mbgl/storage/network_status.cpp", "src/mbgl/storage/resource.cpp", + "src/mbgl/storage/resource_options.cpp", "src/mbgl/storage/resource_transform.cpp", "src/mbgl/storage/response.cpp", "src/mbgl/style/conversion/color_ramp_property_value.cpp", @@ -359,6 +360,7 @@ "mbgl/storage/offline.hpp": "include/mbgl/storage/offline.hpp", "mbgl/storage/online_file_source.hpp": "include/mbgl/storage/online_file_source.hpp", "mbgl/storage/resource.hpp": "include/mbgl/storage/resource.hpp", + "mbgl/storage/resource_options.hpp": "include/mbgl/storage/resource_options.hpp", "mbgl/storage/resource_transform.hpp": "include/mbgl/storage/resource_transform.hpp", "mbgl/storage/response.hpp": "include/mbgl/storage/response.hpp", "mbgl/style/color_ramp_property_value.hpp": "include/mbgl/style/color_ramp_property_value.hpp", @@ -613,6 +615,7 @@ "mbgl/renderer/group_by_layout.hpp": "src/mbgl/renderer/group_by_layout.hpp", "mbgl/renderer/image_atlas.hpp": "src/mbgl/renderer/image_atlas.hpp", "mbgl/renderer/image_manager.hpp": "src/mbgl/renderer/image_manager.hpp", + "mbgl/renderer/image_manager_observer.hpp": "src/mbgl/renderer/image_manager_observer.hpp", "mbgl/renderer/layers/render_background_layer.hpp": "src/mbgl/renderer/layers/render_background_layer.hpp", "mbgl/renderer/layers/render_circle_layer.hpp": "src/mbgl/renderer/layers/render_circle_layer.hpp", "mbgl/renderer/layers/render_custom_layer.hpp": "src/mbgl/renderer/layers/render_custom_layer.hpp", @@ -744,6 +747,7 @@ "mbgl/util/i18n.hpp": "src/mbgl/util/i18n.hpp", "mbgl/util/intersection_tests.hpp": "src/mbgl/util/intersection_tests.hpp", "mbgl/util/io.hpp": "src/mbgl/util/io.hpp", + "mbgl/util/literal.hpp": "src/mbgl/util/literal.hpp", "mbgl/util/longest_common_subsequence.hpp": "src/mbgl/util/longest_common_subsequence.hpp", "mbgl/util/mapbox.hpp": "src/mbgl/util/mapbox.hpp", "mbgl/util/mat2.hpp": "src/mbgl/util/mat2.hpp", diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index ab22404c15..345171b96e 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -10,7 +10,6 @@ #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/style/expression/dsl.hpp> -#include <mbgl/storage/file_source.hpp> #include <boost/function_output_iterator.hpp> diff --git a/src/mbgl/gfx/attribute.hpp b/src/mbgl/gfx/attribute.hpp index 4f44d68d7b..f5188ccfdb 100644 --- a/src/mbgl/gfx/attribute.hpp +++ b/src/mbgl/gfx/attribute.hpp @@ -14,7 +14,7 @@ #define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ struct name_ { \ using Type = ::mbgl::gfx::AttributeType<type_, n_>; \ - static auto name() { \ + static constexpr auto name() { \ return #name_; \ } \ } diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index 90b62c94a4..e898006ff5 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -17,10 +17,14 @@ namespace gfx { class Context { protected: - Context(ContextType type_) : backend(type_) { + Context(ContextType type_, uint32_t maximumVertexBindingCount_) + : backend(type_), maximumVertexBindingCount(maximumVertexBindingCount_) { } +public: const ContextType backend; + static constexpr const uint32_t minimumRequiredVertexBindingCount = 8; + const uint32_t maximumVertexBindingCount; public: Context(Context&&) = delete; @@ -30,6 +34,10 @@ public: virtual ~Context() = default; public: + // Called at the end of a frame. + virtual void performCleanup() = 0; + +public: template <class Vertex> VertexBuffer<Vertex> createVertexBuffer(VertexVector<Vertex>&& v, @@ -92,11 +100,25 @@ public: texture.size = image.size; } + template <typename Image> + void updateTextureSub(Texture& texture, + const Image& image, + const uint16_t offsetX, + const uint16_t offsetY, + TextureChannelDataType type = TextureChannelDataType::UnsignedByte) { + assert(image.size.width + offsetX <= texture.size.width); + assert(image.size.height + offsetY <= texture.size.height); + auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha; + updateTextureResourceSub(*texture.resource, offsetX, offsetY, image.size, image.data.get(), format, type); + } + protected: virtual std::unique_ptr<TextureResource> createTextureResource( Size, const void* data, TexturePixelType, TextureChannelDataType) = 0; virtual void updateTextureResource(const TextureResource&, Size, const void* data, TexturePixelType, TextureChannelDataType) = 0; + virtual void updateTextureResourceSub(const TextureResource&, uint16_t xOffset, uint16_t yOffset, Size, const void* data, + TexturePixelType, TextureChannelDataType) = 0; public: DrawScope createDrawScope() { diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index c4fe8b993f..c7f9ba3fd4 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -3,6 +3,7 @@ #include <mbgl/gfx/attribute.hpp> #include <mbgl/gl/types.hpp> #include <mbgl/util/ignore.hpp> +#include <mbgl/util/literal.hpp> #include <mbgl/util/indexed_tuple.hpp> #include <mbgl/util/optional.hpp> @@ -50,13 +51,15 @@ public: } }; - return Locations{ maybeBindLocation(As::name())... }; + return Locations{ maybeBindLocation( + concat_literals<&string_literal<'a', '_'>::value, &As::name>::value())... }; }()) { } template <class BinaryProgram> AttributeLocations(const BinaryProgram& program) - : locations{ program.attributeLocation(As::name())... } { + : locations{ program.attributeLocation( + concat_literals<&string_literal<'a', '_'>::value, &As::name>::value())... } { } NamedAttributeLocations getNamedLocations() const { @@ -68,7 +71,9 @@ public: } }; - util::ignore({ (maybeAddLocation(As::name(), locations.template get<As>()), 0)... }); + util::ignore({ (maybeAddLocation(concat_literals<&string_literal<'a', '_'>::value, &As::name>::value(), + locations.template get<As>()), + 0)... }); return result; } @@ -90,5 +95,36 @@ public: } }; +template <class> +class AttributeKey; + +constexpr auto attributeDefinePrefix() { + return "#define HAS_UNIFORM_u_"; +} + +template <class... As> +class AttributeKey<TypeList<As...>> final { +public: + static_assert(sizeof...(As) <= 32, "attribute count exceeds 32"); + + static uint32_t compute(const gfx::AttributeBindings<TypeList<As...>>& bindings) { + uint32_t value = 0; + util::ignore( + { (bindings.template get<As>() ? (void)(value |= 1 << TypeIndex<As, As...>::value) + : (void)0, + 0)... }); + return value; + } + + static std::string defines(const gfx::AttributeBindings<TypeList<As...>>& bindings) { + std::string result; + util::ignore({ (!bindings.template get<As>() + ? (void)(result += concat_literals<&attributeDefinePrefix, &As::name, &string_literal<'\n'>::value>::value()) + : (void)0, + 0)... }); + return result; + } +}; + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 5193381251..6cee364379 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -5,6 +5,7 @@ #include <mbgl/gl/texture_resource.hpp> #include <mbgl/gl/draw_scope_resource.hpp> #include <mbgl/gl/texture.hpp> +#include <mbgl/gl/debugging.hpp> #include <mbgl/gl/debugging_extension.hpp> #include <mbgl/gl/vertex_array_extension.hpp> #include <mbgl/gl/program_binary_extension.hpp> @@ -67,7 +68,7 @@ static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch"); Context::Context() - : gfx::Context(gfx::ContextType::OpenGL), maximumVertexBindingCount([] { + : gfx::Context(gfx::ContextType::OpenGL, [] { GLint value; MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); return value; @@ -160,12 +161,10 @@ void Context::enableDebugging() { MBGL_CHECK_ERROR(debugging->debugMessageCallback(extension::Debugging::DebugCallback, nullptr)); } -UniqueShader Context::createShader(ShaderType type, const std::string& source) { +UniqueShader Context::createShader(ShaderType type, const std::initializer_list<const char*>& sources) { UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } }; - const GLchar* sources = source.data(); - const auto lengths = static_cast<GLsizei>(source.length()); - MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths)); + MBGL_CHECK_ERROR(glShaderSource(result, static_cast<GLsizei>(sources.size()), sources.begin(), nullptr)); MBGL_CHECK_ERROR(glCompileShader(result)); GLint status = 0; @@ -547,6 +546,24 @@ void Context::updateTextureResource(const gfx::TextureResource& resource, Enum<gfx::TextureChannelDataType>::to(type), data)); } +void Context::updateTextureResourceSub(const gfx::TextureResource& resource, + const uint16_t xOffset, + const uint16_t yOffset, + const Size size, + const void* data, + gfx::TexturePixelType format, + gfx::TextureChannelDataType type) { + // Always use texture unit 0 for manipulating it. + activeTextureUnit = 0; + texture[0] = static_cast<const gl::TextureResource&>(resource).texture; + MBGL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, + xOffset, yOffset, + size.width, size.height, + Enum<gfx::TexturePixelType>::to(format), + Enum<gfx::TextureChannelDataType>::to(type), data)); +} + + std::unique_ptr<gfx::DrawScopeResource> Context::createDrawScopeResource() { return std::make_unique<gl::DrawScopeResource>(createVertexArray()); } @@ -708,6 +725,19 @@ void Context::draw(const gfx::DrawMode& drawMode, } void Context::performCleanup() { + // TODO: Find a better way to unbind VAOs after we're done with them without introducing + // unnecessary bind(0)/bind(N) sequences. + { + MBGL_DEBUG_GROUP(*this, "cleanup"); + + activeTextureUnit = 1; + texture[1] = 0; + activeTextureUnit = 0; + texture[0] = 0; + + bindVertexArray = 0; + } + for (auto id : abandonedPrograms) { if (program == id) { program.setDirty(); @@ -775,5 +805,9 @@ void Context::performCleanup() { } } +void Context::flush() { + MBGL_CHECK_ERROR(glFinish()); +} + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index fe09390cc6..d46727cb7a 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -46,7 +46,7 @@ public: void enableDebugging(); - UniqueShader createShader(ShaderType type, const std::string& source); + UniqueShader createShader(ShaderType type, const std::initializer_list<const char*>& sources); UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader); UniqueProgram createProgram(BinaryProgramFormat binaryFormat, const std::string& binaryProgram); void verifyProgramLinkage(ProgramID); @@ -56,7 +56,7 @@ public: #if MBGL_HAS_BINARY_PROGRAMS bool supportsProgramBinaries() const; #else - constexpr bool supportsProgramBinaries() const { return false; } + constexpr static bool supportsProgramBinaries() { return false; } #endif optional<std::pair<BinaryProgramFormat, std::string>> getBinaryProgram(ProgramID) const; @@ -110,12 +110,17 @@ public: // 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(); + void performCleanup() override; // Drain pools and remove abandoned objects, in preparation for destroying the store. // Only call this while the OpenGL context is exclusive to this thread. void reset(); + // Flush pending graphics commands. Will block until the pipeline + // is empty. Should be used only with a very good reason because + // it will have a performance impact. + void flush(); + bool empty() const { return pooledTextures.empty() && abandonedPrograms.empty() @@ -172,9 +177,7 @@ public: #endif // MBGL_USE_GLES2 bool supportsHalfFloatTextures = false; - const uint32_t maximumVertexBindingCount; - static constexpr const uint32_t minimumRequiredVertexBindingCount = 8; - + private: State<value::StencilFunc> stencilFunc; State<value::StencilMask> stencilMask; @@ -208,6 +211,7 @@ private: std::unique_ptr<gfx::TextureResource> createTextureResource(Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; void updateTextureResource(const gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; + void updateTextureResourceSub(const gfx::TextureResource&, const uint16_t xOffset, const uint16_t yOffset, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; std::unique_ptr<gfx::DrawScopeResource> createDrawScopeResource() override; diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp index 7b8121f003..54cee5fc09 100644 --- a/src/mbgl/gl/debugging.cpp +++ b/src/mbgl/gl/debugging.cpp @@ -9,8 +9,8 @@ using namespace platform; #ifndef NDEBUG -DebugGroup::DebugGroup(const Context& context_, const std::string& name) : context(context_) { - if (auto debugging = context.getDebuggingExtension()) { +DebugGroup::DebugGroup(const gfx::Context& context_, const std::string& name) : context(context_) { + if (auto debugging = reinterpret_cast<const gl::Context&>(context).getDebuggingExtension()) { if (debugging->pushDebugGroup) { MBGL_CHECK_ERROR(debugging->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, GLsizei(name.size()), name.c_str())); } else if (debugging->pushGroupMarkerEXT) { @@ -20,7 +20,7 @@ DebugGroup::DebugGroup(const Context& context_, const std::string& name) : conte } DebugGroup::~DebugGroup() { - if (auto debugging = context.getDebuggingExtension()) { + if (auto debugging = reinterpret_cast<const gl::Context&>(context).getDebuggingExtension()) { if (debugging->popDebugGroup) { MBGL_CHECK_ERROR(debugging->popDebugGroup()); } else if (debugging->popGroupMarkerEXT) { diff --git a/src/mbgl/gl/debugging.hpp b/src/mbgl/gl/debugging.hpp index d24b727295..d85eb631be 100644 --- a/src/mbgl/gl/debugging.hpp +++ b/src/mbgl/gl/debugging.hpp @@ -5,19 +5,22 @@ #include <string> namespace mbgl { -namespace gl { +namespace gfx { class Context; +} // namespace gfx + +namespace gl { #ifndef NDEBUG class DebugGroup : private util::noncopyable { public: - DebugGroup(const Context&, const std::string&); + DebugGroup(const gfx::Context&, const std::string&); ~DebugGroup(); private: - const Context& context; + const gfx::Context& context; }; #define __MBGL_DEBUG_GROUP_NAME2(counter) __MBGL_DEBUG_GROUP_##counter diff --git a/src/mbgl/gl/features.hpp b/src/mbgl/gl/features.hpp index 1757093967..1da1371e45 100644 --- a/src/mbgl/gl/features.hpp +++ b/src/mbgl/gl/features.hpp @@ -3,5 +3,6 @@ #if __APPLE__ #define MBGL_HAS_BINARY_PROGRAMS 0 #else - #define MBGL_HAS_BINARY_PROGRAMS 1 + // https://github.com/mapbox/mapbox-gl-native/issues/14294 + #define MBGL_HAS_BINARY_PROGRAMS 0 #endif diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index 9028ffdf53..1cec7671a1 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -18,6 +18,7 @@ #include <mbgl/util/logging.hpp> #include <mbgl/programs/program_parameters.hpp> +#include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/programs/gl/shaders.hpp> #include <string> @@ -31,93 +32,128 @@ public: using AttributeList = typename Name::AttributeList; using UniformList = typename Name::UniformList; using TextureList = typename Name::TextureList; - - Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource) - : program( - context.createProgram(context.createShader(ShaderType::Vertex, vertexSource), - context.createShader(ShaderType::Fragment, fragmentSource))), - attributeLocations(context, program) { - // Re-link program after manually binding only active attributes in Attributes::queryLocations - context.linkProgram(program); - - // We have to re-initialize the uniforms state from the bindings as the uniform locations - // get shifted on some implementations - uniformStates.queryLocations(program); - - // Texture units are specified via uniforms as well, so we need query their locations - textureStates.queryLocations(program); - } - template <class BinaryProgram> - Program(Context& context, const BinaryProgram& binaryProgram) - : program(context.createProgram(binaryProgram.format(), binaryProgram.code())), - attributeLocations(binaryProgram) { - uniformStates.loadNamedLocations(binaryProgram); - textureStates.loadNamedLocations(binaryProgram); + Program(ProgramParameters programParameters_) + : programParameters(std::move(programParameters_)) { } - static std::unique_ptr<Program> createProgram(gl::Context& context, - const ProgramParameters& programParameters, - const char* name, - const char* vertexSource_, - const char* fragmentSource_) { - const std::string vertexSource = programs::gl::vertexSource(programParameters, vertexSource_); - const std::string fragmentSource = programs::gl::fragmentSource(programParameters, fragmentSource_); + const ProgramParameters programParameters; + + static constexpr const auto vertexOffset = programs::gl::ShaderSource<Name>::vertexOffset; + static constexpr const auto fragmentOffset = programs::gl::ShaderSource<Name>::fragmentOffset; + + class Instance { + public: + Instance(Context& context, + const std::initializer_list<const char*>& vertexSource, + const std::initializer_list<const char*>& fragmentSource) + : program(context.createProgram( + context.createShader(ShaderType::Vertex, vertexSource), + context.createShader(ShaderType::Fragment, fragmentSource))), + attributeLocations(context, program) { + // Re-link program after manually binding only active attributes in Attributes::queryLocations + context.linkProgram(program); + + // We have to re-initialize the uniforms state from the bindings as the uniform locations + // get shifted on some implementations + uniformStates.queryLocations(program); + + // Texture units are specified via uniforms as well, so we need query their locations + textureStates.queryLocations(program); + } + + template <class BinaryProgram> + Instance(Context& context, const BinaryProgram& binaryProgram) + : program(context.createProgram(binaryProgram.format(), binaryProgram.code())), + attributeLocations(binaryProgram) { + uniformStates.loadNamedLocations(binaryProgram); + textureStates.loadNamedLocations(binaryProgram); + } + + static std::unique_ptr<Instance> + createInstance(gl::Context& context, + const ProgramParameters& programParameters, + const std::string& additionalDefines) { + + #if MBGL_HAS_BINARY_PROGRAMS - optional<std::string> cachePath = programParameters.cachePath(name); - if (cachePath && context.supportsProgramBinaries()) { - const std::string identifier = programs::gl::programIdentifier(vertexSource, fragmentSource); - - try { - if (auto cachedBinaryProgram = util::readFile(*cachePath)) { - const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram)); - if (binaryProgram.identifier() == identifier) { - return std::make_unique<Program>(context, binaryProgram); - } else { - Log::Warning(Event::OpenGL, - "Cached program %s changed. Recompilation required.", - name); + optional<std::string> cachePath = + programParameters.cachePath(programs::gl::ShaderSource<Name>::name); + std::string programIdentifier; + if (cachePath && context.supportsProgramBinaries()) { + programIdentifier = programs::gl::programIdentifier( + programParameters.getDefines(), additionalDefines, programs::gl::preludeHash, + programs::gl::ShaderSource<Name>::hash); + + try { + if (auto cachedBinaryProgram = util::readFile(*cachePath)) { + const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram)); + if (binaryProgram.identifier() == programIdentifier) { + return std::make_unique<Instance>(context, binaryProgram); + } else { + Log::Warning(Event::OpenGL, + "Cached program %s changed. Recompilation required.", + programs::gl::ShaderSource<Name>::name); + } } + } catch (std::runtime_error& error) { + Log::Warning(Event::OpenGL, "Could not load cached program: %s", + error.what()); } - } catch (std::runtime_error& error) { - Log::Warning(Event::OpenGL, "Could not load cached program: %s", - error.what()); } +#endif // Compile the shader - auto result = std::make_unique<Program>(context, vertexSource, fragmentSource); + const std::initializer_list<const char*> vertexSource = { + programParameters.getDefines().c_str(), + additionalDefines.c_str(), + (programs::gl::shaderSource() + programs::gl::vertexPreludeOffset), + (programs::gl::shaderSource() + vertexOffset) + }; + const std::initializer_list<const char*> fragmentSource = { + programParameters.getDefines().c_str(), + additionalDefines.c_str(), + (programs::gl::shaderSource() + programs::gl::fragmentPreludeOffset), + (programs::gl::shaderSource() + fragmentOffset) + }; + auto result = std::make_unique<Instance>(context, vertexSource, fragmentSource); - try { - if (const auto binaryProgram = - result->template get<BinaryProgram>(context, identifier)) { - util::write_file(*cachePath, binaryProgram->serialize()); - Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str()); +#if MBGL_HAS_BINARY_PROGRAMS + if (cachePath && context.supportsProgramBinaries()) { + try { + if (const auto binaryProgram = + result->template get<BinaryProgram>(context, programIdentifier)) { + util::write_file(*cachePath, binaryProgram->serialize()); + Log::Warning(Event::OpenGL, "Caching program in: %s", (*cachePath).c_str()); + } + } catch (std::runtime_error& error) { + Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what()); } - } catch (std::runtime_error& error) { - Log::Warning(Event::OpenGL, "Failed to cache program: %s", error.what()); } - +#endif + return std::move(result); } -#endif - (void)name; - return std::make_unique<Program>(context, vertexSource, fragmentSource); - } - - template <class BinaryProgram> - optional<BinaryProgram> get(Context& context, const std::string& identifier) const { - if (auto binaryProgram = context.getBinaryProgram(program)) { - return BinaryProgram{ binaryProgram->first, - std::move(binaryProgram->second), - identifier, - attributeLocations.getNamedLocations(), - uniformStates.getNamedLocations(), - textureStates.getNamedLocations() }; + template <class BinaryProgram> + optional<BinaryProgram> get(Context& context, const std::string& identifier) const { + if (auto binaryProgram = context.getBinaryProgram(program)) { + return BinaryProgram{ binaryProgram->first, + std::move(binaryProgram->second), + identifier, + attributeLocations.getNamedLocations(), + uniformStates.getNamedLocations(), + textureStates.getNamedLocations() }; + } + return {}; } - return {}; - } + + UniqueProgram program; + gl::AttributeLocations<AttributeList> attributeLocations; + gl::UniformStates<UniformList> uniformStates; + gl::TextureStates<TextureList> textureStates; + }; void draw(gfx::Context& genericContext, const gfx::DrawMode& drawMode, @@ -139,16 +175,29 @@ public: context.setColorMode(colorMode); context.setCullFaceMode(cullFaceMode); - context.program = program; + const uint32_t key = gl::AttributeKey<AttributeList>::compute(attributeBindings); + auto it = instances.find(key); + if (it == instances.end()) { + it = instances + .emplace(key, + Instance::createInstance( + context, + programParameters, + gl::AttributeKey<AttributeList>::defines(attributeBindings))) + .first; + } - uniformStates.bind(uniformValues); + auto& instance = *it->second; + context.program = instance.program; - textureStates.bind(context, textureBindings); + instance.uniformStates.bind(uniformValues); + + instance.textureStates.bind(context, textureBindings); auto& vertexArray = reinterpret_cast<gl::DrawScopeResource&>(*drawScope.resource).vertexArray; vertexArray.bind(context, indexBuffer, - attributeLocations.toBindingArray(attributeBindings)); + instance.attributeLocations.toBindingArray(attributeBindings)); context.draw(drawMode, indexOffset, @@ -156,11 +205,7 @@ public: } private: - UniqueProgram program; - - gl::AttributeLocations<AttributeList> attributeLocations; - gl::UniformStates<UniformList> uniformStates; - gl::TextureStates<TextureList> textureStates; + std::map<uint32_t, std::unique_ptr<Instance>> instances; }; } // namespace gl diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp index 0569adc3b0..44b81f9a45 100644 --- a/src/mbgl/gl/texture.hpp +++ b/src/mbgl/gl/texture.hpp @@ -2,6 +2,7 @@ #include <mbgl/gfx/texture.hpp> #include <mbgl/gl/uniform.hpp> +#include <mbgl/util/literal.hpp> #include <mbgl/util/ignore.hpp> #include <vector> @@ -27,16 +28,19 @@ private: public: void queryLocations(const ProgramID& id) { - state = State{ gl::uniformLocation(id, Ts::name())... }; + state = State{ gl::uniformLocation(id, + concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value())... }; } template <class BinaryProgram> void loadNamedLocations(const BinaryProgram& program) { - state = State{ program.textureLocation(Ts::name())... }; + state = State{ program.textureLocation( + concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value())... }; } NamedUniformLocations getNamedLocations() const { - return NamedUniformLocations{ { Ts::name(), state.template get<Ts>().location }... }; + return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value(), + state.template get<Ts>().location }... }; } void bind(gl::Context& context, const gfx::TextureBindings<TypeList<Ts...>>& bindings) { diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 770f3e2294..89ef675a6b 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -3,6 +3,7 @@ #include <mbgl/gfx/uniform.hpp> #include <mbgl/gl/types.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/literal.hpp> #include <mbgl/util/ignore.hpp> #include <mbgl/util/indexed_tuple.hpp> @@ -73,21 +74,21 @@ public: util::ignore( { // Some shader programs have uniforms declared, but not used, so they're not active. // Therefore, we'll only verify them when they are indeed active. - (active.find(Us::name()) != active.end() - ? verifyUniform<typename Us::Value>(active.at(Us::name())) + (active.find(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value()) != active.end() + ? verifyUniform<typename Us::Value>(active.at(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())) : false)... }); #endif - state = State{ gl::uniformLocation(id, Us::name())... }; + state = State{ gl::uniformLocation(id, concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())... }; } template <class BinaryProgram> void loadNamedLocations(const BinaryProgram& program) { - state = State{ UniformState<typename Us::Value>(program.uniformLocation(Us::name()))... }; + state = State{ UniformState<typename Us::Value>(program.uniformLocation(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value()))... }; } NamedUniformLocations getNamedLocations() const { - return NamedUniformLocations{ { Us::name(), state.template get<Us>().location }... }; + return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value(), state.template get<Us>().location }... }; } void bind(const gfx::UniformValues<TypeList<Us...>>& values) { diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp index 139a42113c..0197df1066 100644 --- a/src/mbgl/layout/symbol_instance.cpp +++ b/src/mbgl/layout/symbol_instance.cpp @@ -5,13 +5,25 @@ namespace mbgl { using namespace style; +namespace { + +const Shaping& getAnyShaping(const ShapedTextOrientations& shapedTextOrientations) { + if (shapedTextOrientations.right) return shapedTextOrientations.right; + if (shapedTextOrientations.center) return shapedTextOrientations.center; + if (shapedTextOrientations.left) return shapedTextOrientations.left; + if (shapedTextOrientations.vertical) return shapedTextOrientations.vertical; + return shapedTextOrientations.horizontal; +} + +} // namespace + SymbolInstance::SymbolInstance(Anchor& anchor_, GeometryCoordinates line_, - const std::pair<Shaping, Shaping>& shapedTextOrientations, + const ShapedTextOrientations& shapedTextOrientations, optional<PositionedIcon> shapedIcon, const SymbolLayoutProperties::Evaluated& layout, const float layoutTextSize, - const float textBoxScale, + const float textBoxScale_, const float textPadding, const SymbolPlacementType textPlacement, const std::array<float, 2> textOffset_, @@ -24,43 +36,70 @@ SymbolInstance::SymbolInstance(Anchor& anchor_, const std::size_t dataFeatureIndex_, const std::u16string& key_, const float overscaling, - const float rotate) : + const float rotate, + float radialTextOffset_) : anchor(anchor_), line(line_), hasText(false), hasIcon(shapedIcon), // Create the collision features that will be used to check whether this symbol instance can be placed - textCollisionFeature(line_, anchor, shapedTextOrientations.first, textBoxScale, textPadding, textPlacement, indexedFeature, overscaling, rotate), + // As a collision approximation, we can use either the vertical or any of the horizontal versions of the feature + textCollisionFeature(line_, anchor, getAnyShaping(shapedTextOrientations), textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, rotate), iconCollisionFeature(line_, anchor, shapedIcon, iconBoxScale, iconPadding, indexedFeature, rotate), + writingModes(WritingModeType::None), layoutFeatureIndex(layoutFeatureIndex_), dataFeatureIndex(dataFeatureIndex_), textOffset(textOffset_), iconOffset(iconOffset_), - key(key_) { + key(key_), + textBoxScale(textBoxScale_), + radialTextOffset(radialTextOffset_), + singleLine(shapedTextOrientations.singleLine) { // Create the quads used for rendering the icon and glyphs. if (shapedIcon) { - iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.first); + iconQuad = getIconQuad(*shapedIcon, layout, layoutTextSize, shapedTextOrientations.horizontal); } - if (shapedTextOrientations.first) { - horizontalGlyphQuads = getGlyphQuads(shapedTextOrientations.first, layout, textPlacement, positions); + + bool singleLineInitialized = false; + const auto initHorizontalGlyphQuads = [&] (SymbolQuads& quads, const Shaping& shaping) { + writingModes |= WritingModeType::Horizontal; + if (!singleLine) { + quads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions); + return; + } + if (!singleLineInitialized) { + rightJustifiedGlyphQuads = getGlyphQuads(shaping, textOffset, layout, textPlacement, positions); + singleLineInitialized = true; + } + }; + + if (shapedTextOrientations.right) { + initHorizontalGlyphQuads(rightJustifiedGlyphQuads, shapedTextOrientations.right); } - if (shapedTextOrientations.second) { - verticalGlyphQuads = getGlyphQuads(shapedTextOrientations.second, layout, textPlacement, positions); + + if (shapedTextOrientations.center) { + initHorizontalGlyphQuads(centerJustifiedGlyphQuads, shapedTextOrientations.center); } - // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap - hasText = horizontalGlyphQuads.size() > 0 || verticalGlyphQuads.size() > 0; - 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; + if (shapedTextOrientations.left) { + initHorizontalGlyphQuads(leftJustifiedGlyphQuads, shapedTextOrientations.left); } + + if (shapedTextOrientations.vertical) { + writingModes |= WritingModeType::Vertical; + verticalGlyphQuads = getGlyphQuads(shapedTextOrientations.vertical, textOffset, layout, textPlacement, positions); + } + + // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap + hasText = !rightJustifiedGlyphQuads.empty() || !centerJustifiedGlyphQuads.empty() || !leftJustifiedGlyphQuads.empty() || !verticalGlyphQuads.empty(); } +optional<size_t> SymbolInstance::getDefaultHorizontalPlacedTextIndex() const { + if (placedRightTextIndex) return placedRightTextIndex; + if (placedCenterTextIndex) return placedCenterTextIndex; + if (placedLeftTextIndex) return placedLeftTextIndex; + return nullopt; +} } // namespace mbgl diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp index 6148d7fe88..5169b16adb 100644 --- a/src/mbgl/layout/symbol_instance.hpp +++ b/src/mbgl/layout/symbol_instance.hpp @@ -11,11 +11,21 @@ namespace mbgl { class Anchor; class IndexedSubfeature; +struct ShapedTextOrientations { + Shaping horizontal; + Shaping vertical; + // The following are used with variable text placement on. + Shaping& right = horizontal; + Shaping center; + Shaping left; + bool singleLine = false; +}; + class SymbolInstance { public: SymbolInstance(Anchor& anchor, GeometryCoordinates line, - const std::pair<Shaping, Shaping>& shapedTextOrientations, + const ShapedTextOrientations& shapedTextOrientations, optional<PositionedIcon> shapedIcon, const style::SymbolLayoutProperties::Evaluated&, const float layoutTextSize, @@ -32,14 +42,21 @@ public: const std::size_t dataFeatureIndex, const std::u16string& key, const float overscaling, - const float rotate); + const float rotate, + float radialTextOffset); + optional<size_t> getDefaultHorizontalPlacedTextIndex() const; Anchor anchor; GeometryCoordinates line; bool hasText; bool hasIcon; - SymbolQuads horizontalGlyphQuads; + // Note: When singleLine == true, only `rightJustifiedGlyphQuads` is populated. + SymbolQuads rightJustifiedGlyphQuads; + SymbolQuads centerJustifiedGlyphQuads; + SymbolQuads leftJustifiedGlyphQuads; + SymbolQuads verticalGlyphQuads; + optional<SymbolQuad> iconQuad; CollisionFeature textCollisionFeature; CollisionFeature iconCollisionFeature; @@ -50,9 +67,14 @@ public: std::array<float, 2> iconOffset; std::u16string key; bool isDuplicate; - optional<size_t> placedTextIndex; + optional<size_t> placedRightTextIndex; + optional<size_t> placedCenterTextIndex; + optional<size_t> placedLeftTextIndex; optional<size_t> placedVerticalTextIndex; optional<size_t> placedIconIndex; + float textBoxScale; + float radialTextOffset; + bool singleLine; uint32_t crossTileID = 0; }; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index c40a705d7f..d1c50d7773 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -174,44 +174,173 @@ bool SymbolLayout::hasSymbolInstances() const { return !symbolInstances.empty(); } +namespace { + +// The radial offset is to the edge of the text box +// In the horizontal direction, the edge of the text box is where glyphs start +// But in the vertical direction, the glyphs appear to "start" at the baseline +// We don't actually load baseline data, but we assume an offset of ONE_EM - 17 +// (see "yOffset" in shaping.js) +const float baselineOffset = 7.0f; + +// We don't care which shaping we get because this is used for collision purposes +// and all the justifications have the same collision box. +const Shaping& getDefaultHorizontalShaping(const ShapedTextOrientations& shapedTextOrientations) { + if (shapedTextOrientations.right) return shapedTextOrientations.right; + if (shapedTextOrientations.center) return shapedTextOrientations.center; + if (shapedTextOrientations.left) return shapedTextOrientations.left; + return shapedTextOrientations.horizontal; +} + +Shaping& shapingForTextJustifyType(ShapedTextOrientations& shapedTextOrientations, style::TextJustifyType type) { + switch(type) { + case style::TextJustifyType::Right: return shapedTextOrientations.right; + case style::TextJustifyType::Left: return shapedTextOrientations.left; + case style::TextJustifyType::Center: return shapedTextOrientations.center; + default: + assert(false); + return shapedTextOrientations.horizontal; + } +} + +} // namespace + +// static +Point<float> SymbolLayout::evaluateRadialOffset(SymbolAnchorType anchor, float radialOffset) { + Point<float> result{}; + // solve for r where r^2 + r^2 = radialOffset^2 + const float sqrt2 = 1.41421356237f; + const float hypotenuse = radialOffset / sqrt2; + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::TopLeft: + result.y = hypotenuse - baselineOffset; + break; + case SymbolAnchorType::BottomRight: + case SymbolAnchorType::BottomLeft: + result.y = -hypotenuse + baselineOffset; + break; + case SymbolAnchorType::Bottom: + result.y = -radialOffset + baselineOffset; + break; + case SymbolAnchorType::Top: + result.y = radialOffset - baselineOffset; + break; + default: + break; + } + + switch (anchor) { + case SymbolAnchorType::TopRight: + case SymbolAnchorType::BottomRight: + result.x = -hypotenuse; + break; + case SymbolAnchorType::TopLeft: + case SymbolAnchorType::BottomLeft: + result.x = hypotenuse; + break; + case SymbolAnchorType::Left: + result.x = radialOffset; + break; + case SymbolAnchorType::Right: + result.x = -radialOffset; + break; + default: + break; + } + + return result; +} + void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions, const ImageMap& imageMap, const ImagePositions& imagePositions) { - const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && - layout.get<SymbolPlacement>() != SymbolPlacementType::Point; + const bool isPointPlacement = layout.get<SymbolPlacement>() == SymbolPlacementType::Point; + const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map && !isPointPlacement; for (auto it = features.begin(); it != features.end(); ++it) { auto& feature = *it; if (feature.geometry.empty()) continue; - std::pair<Shaping, Shaping> shapedTextOrientations; + ShapedTextOrientations shapedTextOrientations; optional<PositionedIcon> shapedIcon; + Point<float> textOffset; // if feature has text, shape the text if (feature.formattedText) { - auto applyShaping = [&] (const TaggedString& formattedText, WritingModeType writingMode) { - const float oneEm = 24.0f; + const float lineHeight = layout.get<TextLineHeight>() * util::ONE_EM; + const float spacing = util::i18n::allowsLetterSpacing(feature.formattedText->rawText()) ? layout.evaluate<TextLetterSpacing>(zoom, feature) * util::ONE_EM : 0.0f; + + auto applyShaping = [&] (const TaggedString& formattedText, WritingModeType writingMode, SymbolAnchorType textAnchor, TextJustifyType textJustify) { const Shaping result = getShaping( /* string */ formattedText, - /* maxWidth: ems */ layout.get<SymbolPlacement>() == SymbolPlacementType::Point ? - layout.evaluate<TextMaxWidth>(zoom, feature) * oneEm : 0, - /* lineHeight: ems */ layout.get<TextLineHeight>() * oneEm, - /* anchor */ layout.evaluate<TextAnchor>(zoom, feature), - /* justify */ layout.evaluate<TextJustify>(zoom, feature), - /* spacing: ems */ util::i18n::allowsLetterSpacing(feature.formattedText->rawText()) ? layout.evaluate<TextLetterSpacing>(zoom, feature) * oneEm : 0.0f, - /* translate */ Point<float>(layout.evaluate<TextOffset>(zoom, feature)[0] * oneEm, layout.evaluate<TextOffset>(zoom, feature)[1] * oneEm), - /* verticalHeight */ oneEm, + /* maxWidth: ems */ isPointPlacement ? layout.evaluate<TextMaxWidth>(zoom, feature) * util::ONE_EM : 0.0f, + /* ems */ lineHeight, + textAnchor, + textJustify, + /* ems */ spacing, + /* translate */ textOffset, /* writingMode */ writingMode, /* bidirectional algorithm object */ bidi, /* glyphs */ glyphMap); return result; }; + const std::vector<style::TextVariableAnchorType> variableTextAnchor = layout.evaluate<TextVariableAnchor>(zoom, feature); + const float radialOffset = layout.evaluate<TextRadialOffset>(zoom, feature); + const SymbolAnchorType textAnchor = layout.evaluate<TextAnchor>(zoom, feature); + if (variableTextAnchor.empty()) { + // Layers with variable anchors use the `text-radial-offset` property and the [x, y] offset vector + // is calculated at placement time instead of layout time + if (radialOffset > 0.0f) { + // The style spec says don't use `text-offset` and `text-radial-offset` together + // but doesn't actually specify what happens if you use both. We go with the radial offset. + textOffset = evaluateRadialOffset(textAnchor, radialOffset * util::ONE_EM); + } else { + textOffset = { layout.evaluate<TextOffset>(zoom, feature)[0] * util::ONE_EM, + layout.evaluate<TextOffset>(zoom, feature)[1] * util::ONE_EM}; + } + } + TextJustifyType textJustify = textAlongLine ? TextJustifyType::Center : layout.evaluate<TextJustify>(zoom, feature); + // If this layer uses text-variable-anchor, generate shapings for all justification possibilities. + if (!textAlongLine && !variableTextAnchor.empty()) { + std::vector<TextJustifyType> justifications; + if (textJustify != TextJustifyType::Auto) { + justifications.push_back(textJustify); + } else { + for (auto anchor : variableTextAnchor) { + justifications.push_back(getAnchorJustification(anchor)); + } + } + for (TextJustifyType justification: justifications) { + Shaping& shapingForJustification = shapingForTextJustifyType(shapedTextOrientations, justification); + if (shapingForJustification) { + continue; + } + // If using text-variable-anchor for the layer, we use a center anchor for all shapings and apply + // the offsets for the anchor in the placement step. + Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, SymbolAnchorType::Center, justification); + if (shaping) { + shapingForJustification = std::move(shaping); + if (shaping.lineCount == 1u) { + shapedTextOrientations.singleLine = true; + break; + } + } + } + } else { + if (textJustify == TextJustifyType::Auto) { + textJustify = getAnchorJustification(textAnchor); + } + Shaping shaping = applyShaping(*feature.formattedText, WritingModeType::Horizontal, textAnchor, textJustify); + if (shaping) { + shapedTextOrientations.horizontal = std::move(shaping); + } - shapedTextOrientations.first = applyShaping(*feature.formattedText, WritingModeType::Horizontal); - - if (util::i18n::allowsVerticalWritingMode(feature.formattedText->rawText()) && textAlongLine) { - feature.formattedText->verticalizePunctuation(); - shapedTextOrientations.second = applyShaping(*feature.formattedText, WritingModeType::Vertical); + if (util::i18n::allowsVerticalWritingMode(feature.formattedText->rawText()) && textAlongLine) { + feature.formattedText->verticalizePunctuation(); + shapedTextOrientations.vertical = applyShaping(*feature.formattedText, WritingModeType::Vertical, textAnchor, textJustify); + } } } @@ -236,8 +365,8 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions } // if either shapedText or icon position is present, add the feature - if (shapedTextOrientations.first || shapedIcon) { - addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositions); + if (getDefaultHorizontalShaping(shapedTextOrientations) || shapedIcon) { + addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositions, textOffset); } feature.geometry.clear(); @@ -248,15 +377,17 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const SymbolFeature& feature, - const std::pair<Shaping, Shaping>& shapedTextOrientations, + const ShapedTextOrientations& shapedTextOrientations, optional<PositionedIcon> shapedIcon, - const GlyphPositions& glyphPositions) { + const GlyphPositions& glyphPositions, + Point<float> offset) { const float minScale = 0.5f; const float glyphSize = 24.0f; const float layoutTextSize = layout.evaluate<TextSize>(zoom + 1, feature); const float layoutIconSize = layout.evaluate<IconSize>(zoom + 1, feature); - const std::array<float, 2> textOffset = layout.evaluate<TextOffset>(zoom, feature); + const std::array<float, 2> textOffset = {{ offset.x, offset.y }}; + const std::array<float, 2> iconOffset = layout.evaluate<IconOffset>(zoom, feature); // To reduce the number of labels that jump around when zooming we need @@ -274,6 +405,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float iconPadding = layout.get<IconPadding>() * tilePixelRatio; const float textMaxAngle = layout.get<TextMaxAngle>() * util::DEG2RAD; const float rotation = layout.evaluate<IconRotate>(zoom, feature); + const float radialTextOffset = layout.evaluate<TextRadialOffset>(zoom, feature) * util::ONE_EM; const SymbolPlacementType textPlacement = layout.get<TextRotationAlignment>() != AlignmentType::Map ? SymbolPlacementType::Point : layout.get<SymbolPlacement>(); @@ -296,7 +428,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, textBoxScale, textPadding, textPlacement, textOffset, iconBoxScale, iconPadding, iconOffset, glyphPositions, indexedFeature, layoutFeatureIndex, feature.index, - feature.formattedText ? feature.formattedText->rawText() : std::u16string(), overscaling, rotation); + feature.formattedText ? feature.formattedText->rawText() : std::u16string(), overscaling, rotation, radialTextOffset); } }; @@ -308,8 +440,8 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, Anchors anchors = getAnchors(line, symbolSpacing, textMaxAngle, - (shapedTextOrientations.second ?: shapedTextOrientations.first).left, - (shapedTextOrientations.second ?: shapedTextOrientations.first).right, + (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).left, + (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).right, (shapedIcon ? shapedIcon->left() : 0), (shapedIcon ? shapedIcon->right() : 0), glyphSize, @@ -329,8 +461,8 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, if (line.size() > 1) { optional<Anchor> anchor = getCenterAnchor(line, textMaxAngle, - (shapedTextOrientations.second ?: shapedTextOrientations.first).left, - (shapedTextOrientations.second ?: shapedTextOrientations.first).right, + (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).left, + (shapedTextOrientations.vertical ?: getDefaultHorizontalShaping(shapedTextOrientations)).right, (shapedIcon ? shapedIcon->left() : 0), (shapedIcon ? shapedIcon->right() : 0), glyphSize, @@ -414,25 +546,41 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn const bool sortFeaturesByY = zOrderByViewport && (layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() || layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>()); - auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances)); + auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio); for (SymbolInstance &symbolInstance : bucket->symbolInstances) { - const bool hasText = symbolInstance.hasText; const bool hasIcon = symbolInstance.hasIcon; + const bool singleLine = symbolInstance.singleLine; const auto& feature = features.at(symbolInstance.layoutFeatureIndex); // Insert final placement into collision tree and add glyphs/icons to buffers if (hasText && feature.formattedText) { - std::size_t index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); - + optional<std::size_t> lastAddedSection; + if (singleLine) { + optional<std::size_t> placedTextIndex; + lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, placedTextIndex, symbolInstance.rightJustifiedGlyphQuads, lastAddedSection); + symbolInstance.placedRightTextIndex = placedTextIndex; + symbolInstance.placedCenterTextIndex = placedTextIndex; + symbolInstance.placedLeftTextIndex = placedTextIndex; + } else { + if (!symbolInstance.rightJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedRightTextIndex, symbolInstance.rightJustifiedGlyphQuads, lastAddedSection); + } + if (!symbolInstance.centerJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedCenterTextIndex, symbolInstance.centerJustifiedGlyphQuads, lastAddedSection); + } + if (!symbolInstance.leftJustifiedGlyphQuads.empty()) { + lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, symbolInstance.writingModes, symbolInstance.placedLeftTextIndex, symbolInstance.leftJustifiedGlyphQuads, lastAddedSection); + } + } if (symbolInstance.writingModes & WritingModeType::Vertical) { - index = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, index); + lastAddedSection = addSymbolGlyphQuads(*bucket, symbolInstance, feature, WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads, lastAddedSection); } - - updatePaintPropertiesForSection(*bucket, feature, index); + assert(lastAddedSection); // True, as hasText == true; + updatePaintPropertiesForSection(*bucket, feature, *lastAddedSection); } if (hasIcon) { @@ -600,7 +748,7 @@ void SymbolLayout::addToDebugBuffers(SymbolBucket& bucket) { // Dynamic vertices are initialized so that the vertex count always agrees with // the layout vertex buffer, but they will always be updated before rendering happens - auto dynamicVertex = CollisionBoxProgram::dynamicVertex(false, false); + auto dynamicVertex = CollisionBoxProgram::dynamicVertex(false, false, {}); collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); collisionBuffer.dynamicVertices.emplace_back(dynamicVertex); diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index 53c66d31fe..d88c79c552 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -46,12 +46,15 @@ public: const std::string bucketLeaderID; std::vector<SymbolInstance> symbolInstances; + static Point<float> evaluateRadialOffset(style::SymbolAnchorType anchor, float radialOffset); + private: void addFeature(const size_t, const SymbolFeature&, - const std::pair<Shaping, Shaping>& shapedTextOrientations, + const ShapedTextOrientations& shapedTextOrientations, optional<PositionedIcon> shapedIcon, - const GlyphPositions&); + const GlyphPositions&, + Point<float> textOffset); bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&); std::map<std::u16string, std::vector<Anchor>> compareText; diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp index dff2a569ac..b7858f8deb 100644 --- a/src/mbgl/layout/symbol_projection.cpp +++ b/src/mbgl/layout/symbol_projection.cpp @@ -291,9 +291,9 @@ namespace mbgl { gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray, const Point<float>& projectedAnchorPoint, const float aspectRatio) { - const float fontScale = fontSize / 24.0; - const float lineOffsetX = symbol.lineOffset[0] * fontSize; - const float lineOffsetY = symbol.lineOffset[1] * fontSize; + const float fontScale = fontSize / util::ONE_EM; + const float lineOffsetX = symbol.lineOffset[0] * fontScale; + const float lineOffsetY = symbol.lineOffset[1] * fontScale; std::vector<PlacedGlyph> placedGlyphs; if (symbol.glyphOffsets.size() > 1) { diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp index 03e660b474..3699eee290 100644 --- a/src/mbgl/layout/symbol_projection.hpp +++ b/src/mbgl/layout/symbol_projection.hpp @@ -60,4 +60,9 @@ namespace mbgl { const mat4& labelPlaneMatrix, const bool returnTileDistance); + void hideGlyphs(std::size_t numGlyphs, gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertices); + void addDynamicAttributes(const Point<float>& anchorPoint, + const float angle, + gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertices); + } // end namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index f545fc8095..b22a9ee2f2 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -27,24 +27,16 @@ namespace mbgl { using namespace style; -Map::Map(RendererFrontend& rendererFrontend, - MapObserver& mapObserver, - const Size size, - const float pixelRatio, - FileSource& fileSource, +Map::Map(RendererFrontend& frontend, + MapObserver& observer, Scheduler& scheduler, - const MapOptions& options) - : impl(std::make_unique<Impl>(*this, - rendererFrontend, - mapObserver, - fileSource, - scheduler, - size, - pixelRatio, - options.mapMode(), - options.constrainMode(), - options.viewportMode(), - options.crossSourceCollisions())) {} + const MapOptions& mapOptions, + const ResourceOptions& resourceOptions) + : impl(std::make_unique<Impl>(frontend, observer, scheduler, + FileSource::getSharedFileSource(resourceOptions), + mapOptions)) {} + +Map::Map(std::unique_ptr<Impl> impl_) : impl(std::move(impl_)) {} Map::~Map() = default; @@ -139,9 +131,7 @@ CameraOptions Map::getCameraOptions(const EdgeInsets& padding) const { } void Map::jumpTo(const CameraOptions& camera) { - impl->cameraMutated = true; - impl->transform.jumpTo(camera); - impl->onUpdate(); + impl->jumpTo(camera); } void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) { @@ -214,8 +204,13 @@ CameraOptions cameraForLatLngs(const std::vector<LatLng>& latLngs, const Transfo scaleY -= (padding.top() + padding.bottom()) / height; minScale = util::min(scaleX, scaleY); } - double zoom = transform.getZoom() + util::log2(minScale); - zoom = util::clamp(zoom, transform.getState().getMinZoom(), transform.getState().getMaxZoom()); + + double zoom = transform.getZoom(); + if (minScale > 0) { + zoom = util::clamp(zoom + util::log2(minScale), transform.getState().getMinZoom(), transform.getState().getMaxZoom()); + } else { + Log::Error(Event::General, "Unable to calculate appropriate zoom level for bounds. Vertical or horizontal padding is greater than map's height or width."); + } // Calculate the center point of a virtual bounds that is extended in all directions by padding. ScreenCoordinate centerPixel = nePixel + swPixel; @@ -312,48 +307,37 @@ BoundOptions Map::getBounds() const { .withMaxZoom(impl->transform.getState().getMaxZoom()); } -#pragma mark - Size +#pragma mark - Map options void Map::setSize(const Size size) { impl->transform.resize(size); impl->onUpdate(); } -Size Map::getSize() const { - return impl->transform.getState().getSize(); -} - -#pragma mark - North Orientation - void Map::setNorthOrientation(NorthOrientation orientation) { impl->transform.setNorthOrientation(orientation); impl->onUpdate(); } -NorthOrientation Map::getNorthOrientation() const { - return impl->transform.getNorthOrientation(); -} - -#pragma mark - Constrain mode - void Map::setConstrainMode(mbgl::ConstrainMode mode) { impl->transform.setConstrainMode(mode); impl->onUpdate(); } -ConstrainMode Map::getConstrainMode() const { - return impl->transform.getConstrainMode(); -} - -#pragma mark - Viewport mode - void Map::setViewportMode(mbgl::ViewportMode mode) { impl->transform.setViewportMode(mode); impl->onUpdate(); } -ViewportMode Map::getViewportMode() const { - return impl->transform.getViewportMode(); +MapOptions Map::getMapOptions() const { + return std::move(MapOptions() + .withMapMode(impl->mode) + .withConstrainMode(impl->transform.getConstrainMode()) + .withViewportMode(impl->transform.getViewportMode()) + .withCrossSourceCollisions(impl->crossSourceCollisions) + .withNorthOrientation(impl->transform.getNorthOrientation()) + .withSize(impl->transform.getState().getSize()) + .withPixelRatio(impl->pixelRatio)); } #pragma mark - Projection mode diff --git a/src/mbgl/map/map_impl.cpp b/src/mbgl/map/map_impl.cpp index 84cf324722..1ec7255822 100644 --- a/src/mbgl/map/map_impl.cpp +++ b/src/mbgl/map/map_impl.cpp @@ -1,39 +1,31 @@ #include <mbgl/layermanager/layer_manager.hpp> #include <mbgl/map/map_impl.hpp> #include <mbgl/renderer/update_parameters.hpp> +#include <mbgl/storage/file_source.hpp> #include <mbgl/style/style_impl.hpp> #include <mbgl/util/exception.hpp> namespace mbgl { -Map::Impl::Impl(Map& map_, - RendererFrontend& frontend, - MapObserver& mapObserver, - FileSource& fileSource_, +Map::Impl::Impl(RendererFrontend& frontend_, + MapObserver& observer_, Scheduler& scheduler_, - Size size_, - float pixelRatio_, - MapMode mode_, - ConstrainMode constrainMode_, - ViewportMode viewportMode_, - bool crossSourceCollisions_) - : map(map_), - observer(mapObserver), - rendererFrontend(frontend), - fileSource(fileSource_), - scheduler(scheduler_), - transform(observer, - constrainMode_, - viewportMode_), - mode(mode_), - pixelRatio(pixelRatio_), - crossSourceCollisions(crossSourceCollisions_), - style(std::make_unique<style::Style>(scheduler, fileSource, pixelRatio)), - annotationManager(*style) { - + std::shared_ptr<FileSource> fileSource_, + const MapOptions& mapOptions) + : observer(observer_), + rendererFrontend(frontend_), + scheduler(scheduler_), + transform(observer, mapOptions.constrainMode(), mapOptions.viewportMode()), + mode(mapOptions.mapMode()), + pixelRatio(mapOptions.pixelRatio()), + crossSourceCollisions(mapOptions.crossSourceCollisions()), + fileSource(std::move(fileSource_)), + style(std::make_unique<style::Style>(scheduler, *fileSource, pixelRatio)), + annotationManager(*style) { + transform.setNorthOrientation(mapOptions.northOrientation()); style->impl->setObserver(this); rendererFrontend.setObserver(*this); - transform.resize(size_); + transform.resize(mapOptions.size()); } Map::Impl::~Impl() { @@ -73,7 +65,7 @@ void Map::Impl::onUpdate() { style->impl->getSourceImpls(), style->impl->getLayerImpls(), annotationManager, - fileSource, + *fileSource, prefetchZoomDelta, bool(stillImageRequest), crossSourceCollisions @@ -90,7 +82,7 @@ void Map::Impl::onStyleLoading() { void Map::Impl::onStyleLoaded() { if (!cameraMutated) { - map.jumpTo(style->getDefaultCamera()); + jumpTo(style->getDefaultCamera()); } if (LayerManager::annotationsEnabled) { annotationManager.onStyleLoaded(); @@ -173,4 +165,20 @@ void Map::Impl::onDidFinishRenderingMap() { } }; +void Map::Impl::jumpTo(const CameraOptions& camera) { + cameraMutated = true; + transform.jumpTo(camera); + onUpdate(); +} + +void Map::Impl::onStyleImageMissing(const std::string& id, std::function<void()> done) { + + if (style->getImage(id) == nullptr) { + observer.onStyleImageMissing(id); + } + + done(); + onUpdate(); +} + } // namespace mbgl diff --git a/src/mbgl/map/map_impl.hpp b/src/mbgl/map/map_impl.hpp index 32dc728b70..f233f78275 100644 --- a/src/mbgl/map/map_impl.hpp +++ b/src/mbgl/map/map_impl.hpp @@ -1,14 +1,15 @@ #pragma once +#include <mbgl/actor/actor.hpp> #include <mbgl/actor/scheduler.hpp> #include <mbgl/annotation/annotation_manager.hpp> #include <mbgl/map/map.hpp> #include <mbgl/map/map_observer.hpp> +#include <mbgl/map/map_options.hpp> #include <mbgl/map/mode.hpp> #include <mbgl/map/transform.hpp> #include <mbgl/renderer/renderer_frontend.hpp> #include <mbgl/renderer/renderer_observer.hpp> -#include <mbgl/storage/file_source.hpp> #include <mbgl/style/observer.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/style.hpp> @@ -16,6 +17,9 @@ namespace mbgl { +class FileSource; +class ResourceTransform; + struct StillImageRequest { StillImageRequest(Map::StillImageCallback&& callback_) : callback(std::move(callback_)) { @@ -26,20 +30,7 @@ struct StillImageRequest { class Map::Impl : public style::Observer, public RendererObserver { public: - Impl(Map&, - RendererFrontend&, - MapObserver&, - FileSource&, - Scheduler&, - - Size size, - float pixelRatio, - - MapMode, - ConstrainMode, - ViewportMode, - bool crossSourceCollisions); - + Impl(RendererFrontend&, MapObserver&, Scheduler&, std::shared_ptr<FileSource>, const MapOptions&); ~Impl() final; // StyleObserver @@ -56,11 +47,13 @@ public: void onDidFinishRenderingFrame(RenderMode, bool) final; void onWillStartRenderingMap() final; void onDidFinishRenderingMap() final; + void onStyleImageMissing(const std::string&, std::function<void()>) final; + + // Map + void jumpTo(const CameraOptions&); - Map& map; MapObserver& observer; RendererFrontend& rendererFrontend; - FileSource& fileSource; Scheduler& scheduler; Transform transform; @@ -71,6 +64,8 @@ public: MapDebugOptions debugOptions { MapDebugOptions::NoDebug }; + std::shared_ptr<FileSource> fileSource; + std::unique_ptr<style::Style> style; AnnotationManager annotationManager; diff --git a/src/mbgl/map/map_options.cpp b/src/mbgl/map/map_options.cpp index 118fcaf3df..4cebb6adab 100644 --- a/src/mbgl/map/map_options.cpp +++ b/src/mbgl/map/map_options.cpp @@ -1,7 +1,4 @@ #include <mbgl/map/map_options.hpp> -#include <mbgl/util/constants.hpp> - -#include <cassert> namespace mbgl { @@ -10,14 +7,16 @@ public: MapMode mapMode = MapMode::Continuous; ConstrainMode constrainMode = ConstrainMode::HeightOnly; ViewportMode viewportMode = ViewportMode::Default; - std::string cachePath; - std::string assetRoot; - uint64_t maximumSize{mbgl::util::DEFAULT_MAX_CACHE_SIZE}; + NorthOrientation orientation = NorthOrientation::Upwards; bool crossSourceCollisions = true; + Size size = { 64, 64 }; + float pixelRatio = 1.0; }; -MapOptions::MapOptions() : impl_(std::make_shared<MapOptions::Impl>()) {} +// These requires the complete type of Impl. +MapOptions::MapOptions() : impl_(std::make_unique<Impl>()) {} MapOptions::~MapOptions() = default; +MapOptions::MapOptions(MapOptions&&) noexcept = default; MapOptions& MapOptions::withMapMode(MapMode mode) { impl_->mapMode = mode; @@ -46,40 +45,40 @@ ViewportMode MapOptions::viewportMode() const { return impl_->viewportMode; } -MapOptions& MapOptions::withCachePath(std::string path) { - impl_->cachePath = std::move(path); +MapOptions& MapOptions::withCrossSourceCollisions(bool enableCollisions) { + impl_->crossSourceCollisions = enableCollisions; return *this; } -const std::string& MapOptions::cachePath() const { - return impl_->cachePath; +bool MapOptions::crossSourceCollisions() const { + return impl_->crossSourceCollisions; } -MapOptions& MapOptions::withAssetRoot(std::string path) { - impl_->assetRoot = std::move(path); +MapOptions& MapOptions::withNorthOrientation(NorthOrientation orientation) { + impl_->orientation = orientation; return *this; } -const std::string& MapOptions::assetRoot() const { - return impl_->assetRoot; +NorthOrientation MapOptions::northOrientation() const { + return impl_->orientation; } -MapOptions& MapOptions::withMaximumCacheSize(uint64_t size) { - impl_->maximumSize = size; +MapOptions& MapOptions::withSize(Size size_) { + impl_->size = size_; return *this; } -uint64_t MapOptions::maximumCacheSize() const { - return impl_->maximumSize; +Size MapOptions::size() const { + return impl_->size; } -MapOptions& MapOptions::withCrossSourceCollisions(bool enableCollisions) { - impl_->crossSourceCollisions = enableCollisions; +MapOptions& MapOptions::withPixelRatio(float ratio) { + impl_->pixelRatio = ratio; return *this; } -bool MapOptions::crossSourceCollisions() const { - return impl_->crossSourceCollisions; +float MapOptions::pixelRatio() const { + return impl_->pixelRatio; } } // namespace mbgl diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp index 6106eedb53..803a9db503 100644 --- a/src/mbgl/programs/attributes.hpp +++ b/src/mbgl/programs/attributes.hpp @@ -7,52 +7,54 @@ namespace attributes { // Layout attributes -MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos); -MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude); -MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset); -MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_normal); -MBGL_DEFINE_ATTRIBUTE(float, 3, a_projected_pos); -MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_label_pos); -MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_anchor_pos); -MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos); -MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_normal_ed); -MBGL_DEFINE_ATTRIBUTE(uint8_t, 1, a_fade_opacity); -MBGL_DEFINE_ATTRIBUTE(uint8_t, 2, a_placed); -MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, a_size); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_offset); -MBGL_DEFINE_ATTRIBUTE(float, 2, a_shift); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, extrude); +MBGL_DEFINE_ATTRIBUTE(int16_t, 4, pos_offset); +MBGL_DEFINE_ATTRIBUTE(int16_t, 4, pos_normal); +MBGL_DEFINE_ATTRIBUTE(float, 3, projected_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, label_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 2, anchor_pos); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, texture_pos); +MBGL_DEFINE_ATTRIBUTE(int16_t, 4, normal_ed); +MBGL_DEFINE_ATTRIBUTE(uint8_t, 1, fade_opacity); +MBGL_DEFINE_ATTRIBUTE(uint8_t, 2, placed); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, size); +MBGL_DEFINE_ATTRIBUTE(float, 1, offset); +MBGL_DEFINE_ATTRIBUTE(float, 2, shift); template <typename T, std::size_t N> -struct a_data { +struct data { using Type = gfx::AttributeType<T, N>; - static auto name() { return "a_data"; } + static constexpr auto name() { + return "data"; + } }; // Paint attributes -MBGL_DEFINE_ATTRIBUTE(float, 2, a_color); -MBGL_DEFINE_ATTRIBUTE(float, 2, a_fill_color); -MBGL_DEFINE_ATTRIBUTE(float, 2, a_halo_color); -MBGL_DEFINE_ATTRIBUTE(float, 2, a_stroke_color); -MBGL_DEFINE_ATTRIBUTE(float, 2, a_outline_color); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_opacity); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_stroke_opacity); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_blur); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_radius); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_width); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_floorwidth); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_height); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_base); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_gapwidth); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_stroke_width); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_halo_width); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_halo_blur); -MBGL_DEFINE_ATTRIBUTE(float, 1, a_weight); -MBGL_DEFINE_ATTRIBUTE(uint16_t, 4, a_pattern_to); -MBGL_DEFINE_ATTRIBUTE(uint16_t, 4, a_pattern_from); +MBGL_DEFINE_ATTRIBUTE(float, 2, color); +MBGL_DEFINE_ATTRIBUTE(float, 2, fill_color); +MBGL_DEFINE_ATTRIBUTE(float, 2, halo_color); +MBGL_DEFINE_ATTRIBUTE(float, 2, stroke_color); +MBGL_DEFINE_ATTRIBUTE(float, 2, outline_color); +MBGL_DEFINE_ATTRIBUTE(float, 1, opacity); +MBGL_DEFINE_ATTRIBUTE(float, 1, stroke_opacity); +MBGL_DEFINE_ATTRIBUTE(float, 1, blur); +MBGL_DEFINE_ATTRIBUTE(float, 1, radius); +MBGL_DEFINE_ATTRIBUTE(float, 1, width); +MBGL_DEFINE_ATTRIBUTE(float, 1, floorwidth); +MBGL_DEFINE_ATTRIBUTE(float, 1, height); +MBGL_DEFINE_ATTRIBUTE(float, 1, base); +MBGL_DEFINE_ATTRIBUTE(float, 1, gapwidth); +MBGL_DEFINE_ATTRIBUTE(float, 1, stroke_width); +MBGL_DEFINE_ATTRIBUTE(float, 1, halo_width); +MBGL_DEFINE_ATTRIBUTE(float, 1, halo_blur); +MBGL_DEFINE_ATTRIBUTE(float, 1, weight); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 4, pattern_to); +MBGL_DEFINE_ATTRIBUTE(uint16_t, 4, pattern_from); } // namespace attributes -using PositionOnlyLayoutAttributes = TypeList<attributes::a_pos>; +using PositionOnlyLayoutAttributes = TypeList<attributes::pos>; } // namespace mbgl diff --git a/src/mbgl/programs/background_program.cpp b/src/mbgl/programs/background_program.cpp index 7d68f62fb1..772d481578 100644 --- a/src/mbgl/programs/background_program.cpp +++ b/src/mbgl/programs/background_program.cpp @@ -28,21 +28,21 @@ BackgroundPatternProgram::layoutUniformValues(mat4 matrix, int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; return { - uniforms::u_matrix::Value( matrix ), - uniforms::u_opacity::Value( opacity ), - uniforms::u_texsize::Value( atlasSize ), - uniforms::u_pattern_tl_a::Value( a.tl() ), - uniforms::u_pattern_br_a::Value( a.br() ), - uniforms::u_pattern_tl_b::Value( b.tl() ), - uniforms::u_pattern_br_b::Value( b.br() ), - uniforms::u_pattern_size_a::Value( a.displaySize() ), - uniforms::u_pattern_size_b::Value( b.displaySize() ), - uniforms::u_scale_a::Value( fading.fromScale ), - uniforms::u_scale_b::Value( fading.toScale ), - uniforms::u_mix::Value( fading.t ), - uniforms::u_pixel_coord_upper::Value( std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }}), - uniforms::u_pixel_coord_lower::Value( std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF)}}), - uniforms::u_tile_units_to_pixels::Value( 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()) ), + uniforms::matrix::Value( matrix ), + uniforms::opacity::Value( opacity ), + uniforms::texsize::Value( atlasSize ), + uniforms::pattern_tl_a::Value( a.tl() ), + uniforms::pattern_br_a::Value( a.br() ), + uniforms::pattern_tl_b::Value( b.tl() ), + uniforms::pattern_br_b::Value( b.br() ), + uniforms::pattern_size_a::Value( a.displaySize() ), + uniforms::pattern_size_b::Value( b.displaySize() ), + uniforms::scale_a::Value( fading.fromScale ), + uniforms::scale_b::Value( fading.toScale ), + uniforms::mix::Value( fading.t ), + uniforms::pixel_coord_upper::Value( std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }}), + uniforms::pixel_coord_lower::Value( std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF)}}), + uniforms::tile_units_to_pixels::Value( 1.0f / tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()) ), }; } diff --git a/src/mbgl/programs/background_program.hpp b/src/mbgl/programs/background_program.hpp index b1ade6dc84..dd0683776c 100644 --- a/src/mbgl/programs/background_program.hpp +++ b/src/mbgl/programs/background_program.hpp @@ -18,26 +18,26 @@ template <class> class Faded; using BackgroundLayoutAttributes = PositionOnlyLayoutAttributes; using BackgroundUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_color, - uniforms::u_opacity>; + uniforms::matrix, + uniforms::color, + uniforms::opacity>; using BackgroundPatternUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_opacity, - uniforms::u_texsize, - uniforms::u_pattern_tl_a, - uniforms::u_pattern_br_a, - uniforms::u_pattern_tl_b, - uniforms::u_pattern_br_b, - uniforms::u_pattern_size_a, - uniforms::u_pattern_size_b, - uniforms::u_scale_a, - uniforms::u_scale_b, - uniforms::u_mix, - uniforms::u_pixel_coord_upper, - uniforms::u_pixel_coord_lower, - uniforms::u_tile_units_to_pixels>; + uniforms::matrix, + uniforms::opacity, + uniforms::texsize, + uniforms::pattern_tl_a, + uniforms::pattern_br_a, + uniforms::pattern_tl_b, + uniforms::pattern_br_b, + uniforms::pattern_size_a, + uniforms::pattern_size_b, + uniforms::scale_a, + uniforms::scale_b, + uniforms::mix, + uniforms::pixel_coord_upper, + uniforms::pixel_coord_lower, + uniforms::tile_units_to_pixels>; class BackgroundProgram : public Program< BackgroundProgram, @@ -57,7 +57,7 @@ class BackgroundPatternProgram : public Program< BackgroundLayoutAttributes, BackgroundPatternUniforms, TypeList< - textures::u_image>, + textures::image>, style::Properties<>> { public: diff --git a/src/mbgl/programs/circle_program.hpp b/src/mbgl/programs/circle_program.hpp index 0caa1b2a15..2b218d1768 100644 --- a/src/mbgl/programs/circle_program.hpp +++ b/src/mbgl/programs/circle_program.hpp @@ -9,20 +9,20 @@ namespace mbgl { namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_scale_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(bool, scale_with_map); } // namespace uniforms class CircleProgram : public Program< CircleProgram, gfx::PrimitiveType::Triangle, TypeList< - attributes::a_pos>, + attributes::pos>, TypeList< - uniforms::u_matrix, - uniforms::u_scale_with_map, - uniforms::u_extrude_scale, - uniforms::u_camera_to_center_distance, - uniforms::u_pitch_with_map>, + uniforms::matrix, + uniforms::scale_with_map, + uniforms::extrude_scale, + uniforms::camera_to_center_distance, + uniforms::pitch_with_map>, TypeList<>, style::CirclePaintProperties> { @@ -52,7 +52,7 @@ class CircleLayerPrograms final : public LayerTypePrograms { public: CircleLayerPrograms(gfx::Context& context, const ProgramParameters& programParameters) : circle(context, programParameters) {} - ProgramMap<CircleProgram> circle; + CircleProgram circle; }; } // namespace mbgl diff --git a/src/mbgl/programs/clipping_mask_program.hpp b/src/mbgl/programs/clipping_mask_program.hpp index 874708a52f..14d66a8703 100644 --- a/src/mbgl/programs/clipping_mask_program.hpp +++ b/src/mbgl/programs/clipping_mask_program.hpp @@ -12,7 +12,7 @@ class ClippingMaskProgram : public Program< gfx::PrimitiveType::Triangle, PositionOnlyLayoutAttributes, TypeList< - uniforms::u_matrix>, + uniforms::matrix>, TypeList<>, style::Properties<>> { diff --git a/src/mbgl/programs/collision_box_program.hpp b/src/mbgl/programs/collision_box_program.hpp index 7b81752a94..677704b154 100644 --- a/src/mbgl/programs/collision_box_program.hpp +++ b/src/mbgl/programs/collision_box_program.hpp @@ -11,21 +11,20 @@ namespace mbgl { using CollisionBoxLayoutAttributes = TypeList< - attributes::a_pos, - attributes::a_anchor_pos, - attributes::a_extrude, - attributes::a_shift>; + attributes::pos, + attributes::anchor_pos, + attributes::extrude>; -using CollisionBoxDynamicAttributes = TypeList<attributes::a_placed>; +using CollisionBoxDynamicAttributes = TypeList<attributes::placed, attributes::shift>; class CollisionBoxProgram : public Program< CollisionBoxProgram, gfx::PrimitiveType::Line, TypeListConcat<CollisionBoxLayoutAttributes, CollisionBoxDynamicAttributes>, TypeList< - uniforms::u_matrix, - uniforms::u_extrude_scale, - uniforms::u_camera_to_center_distance>, + uniforms::matrix, + uniforms::extrude_scale, + uniforms::camera_to_center_distance>, TypeList<>, style::Properties<>> { @@ -45,17 +44,14 @@ public: {{ static_cast<int16_t>(::round(o.x)), static_cast<int16_t>(::round(o.y)) - }}, - {{ - 0.0f, - 0.0f }} }; } - static gfx::Vertex<CollisionBoxDynamicAttributes> dynamicVertex(bool placed, bool notUsed) { + static gfx::Vertex<CollisionBoxDynamicAttributes> dynamicVertex(bool placed, bool notUsed, Point<float> shift) { return { - {{ static_cast<uint8_t>(placed), static_cast<uint8_t>(notUsed) }} + {{ static_cast<uint8_t>(placed), static_cast<uint8_t>(notUsed) }}, + {{ shift.x, shift.y }} }; } @@ -116,10 +112,10 @@ class CollisionCircleProgram : public Program< gfx::PrimitiveType::Triangle, TypeListConcat<CollisionBoxLayoutAttributes, CollisionBoxDynamicAttributes>, TypeList< - uniforms::u_matrix, - uniforms::u_extrude_scale, - uniforms::u_overscale_factor, - uniforms::u_camera_to_center_distance>, + uniforms::matrix, + uniforms::extrude_scale, + uniforms::overscale_factor, + uniforms::camera_to_center_distance>, TypeList<>, style::Properties<>> { @@ -139,10 +135,6 @@ public: {{ static_cast<int16_t>(::round(o.x)), static_cast<int16_t>(::round(o.y)) - }}, - {{ - 0.0f, - 0.0f }} }; } diff --git a/src/mbgl/programs/debug_program.hpp b/src/mbgl/programs/debug_program.hpp index 61125b55bf..f1782e19e3 100644 --- a/src/mbgl/programs/debug_program.hpp +++ b/src/mbgl/programs/debug_program.hpp @@ -11,10 +11,10 @@ class DebugProgram : public Program< DebugProgram, gfx::PrimitiveType::Line, TypeList< - attributes::a_pos>, + attributes::pos>, TypeList< - uniforms::u_matrix, - uniforms::u_color>, + uniforms::matrix, + uniforms::color>, TypeList<>, style::Properties<>> { diff --git a/src/mbgl/programs/extrusion_texture_program.hpp b/src/mbgl/programs/extrusion_texture_program.hpp index bdeeabb8cd..10dfdc8a16 100644 --- a/src/mbgl/programs/extrusion_texture_program.hpp +++ b/src/mbgl/programs/extrusion_texture_program.hpp @@ -12,13 +12,13 @@ namespace mbgl { class ExtrusionTextureProgram : public Program< ExtrusionTextureProgram, gfx::PrimitiveType::Triangle, - TypeList<attributes::a_pos>, + TypeList<attributes::pos>, TypeList< - uniforms::u_matrix, - uniforms::u_world, - uniforms::u_opacity>, + uniforms::matrix, + uniforms::world, + uniforms::opacity>, TypeList< - textures::u_image>, + textures::image>, style::Properties<>> { public: using Program::Program; diff --git a/src/mbgl/programs/fill_extrusion_program.cpp b/src/mbgl/programs/fill_extrusion_program.cpp index 7688d09299..d301f32707 100644 --- a/src/mbgl/programs/fill_extrusion_program.cpp +++ b/src/mbgl/programs/fill_extrusion_program.cpp @@ -38,10 +38,10 @@ float lightIntensity(const EvaluatedLight& light) { FillExtrusionProgram::LayoutUniformValues FillExtrusionProgram::layoutUniformValues( mat4 matrix, const TransformState& state, const EvaluatedLight& light) { return { - uniforms::u_matrix::Value( matrix ), - uniforms::u_lightcolor::Value( lightColor(light) ), - uniforms::u_lightpos::Value( lightPosition(light, state) ), - uniforms::u_lightintensity::Value( lightIntensity(light) ) + uniforms::matrix::Value( matrix ), + uniforms::lightcolor::Value( lightColor(light) ), + uniforms::lightpos::Value( lightPosition(light, state) ), + uniforms::lightintensity::Value( lightIntensity(light) ) }; } @@ -60,16 +60,16 @@ FillExtrusionPatternProgram::layoutUniformValues(mat4 matrix, int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; return { - uniforms::u_matrix::Value( matrix ), - uniforms::u_scale::Value( {{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale}} ), - uniforms::u_texsize::Value( atlasSize ), - uniforms::u_fade::Value( crossfade.t ), - uniforms::u_pixel_coord_upper::Value( std::array<float, 2>{{ float(pixelX >> 16), float(pixelY >> 16) }} ), - uniforms::u_pixel_coord_lower::Value( std::array<float, 2>{{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} ), - uniforms::u_height_factor::Value( heightFactor ), - uniforms::u_lightcolor::Value( lightColor(light) ), - uniforms::u_lightpos::Value( lightPosition(light, state) ), - uniforms::u_lightintensity::Value( lightIntensity(light) ), + uniforms::matrix::Value( matrix ), + uniforms::scale::Value( {{pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale}} ), + uniforms::texsize::Value( atlasSize ), + uniforms::fade::Value( crossfade.t ), + uniforms::pixel_coord_upper::Value( std::array<float, 2>{{ float(pixelX >> 16), float(pixelY >> 16) }} ), + uniforms::pixel_coord_lower::Value( std::array<float, 2>{{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} ), + uniforms::height_factor::Value( heightFactor ), + uniforms::lightcolor::Value( lightColor(light) ), + uniforms::lightpos::Value( lightPosition(light, state) ), + uniforms::lightintensity::Value( lightIntensity(light) ), }; } diff --git a/src/mbgl/programs/fill_extrusion_program.hpp b/src/mbgl/programs/fill_extrusion_program.hpp index e1c3ca7f17..85e2ff3caf 100644 --- a/src/mbgl/programs/fill_extrusion_program.hpp +++ b/src/mbgl/programs/fill_extrusion_program.hpp @@ -22,33 +22,33 @@ class TransformState; template <class> class Faded; namespace uniforms { -MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_lightpos); -MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_lightcolor); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_lightintensity); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_height_factor); +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, lightpos); +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, lightcolor); +MBGL_DEFINE_UNIFORM_SCALAR(float, lightintensity); +MBGL_DEFINE_UNIFORM_SCALAR(float, height_factor); } // namespace uniforms using FillExtrusionLayoutAttributes = TypeList< - attributes::a_pos, - attributes::a_normal_ed>; + attributes::pos, + attributes::normal_ed>; using FillExtrusionUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_lightcolor, - uniforms::u_lightpos, - uniforms::u_lightintensity>; + uniforms::matrix, + uniforms::lightcolor, + uniforms::lightpos, + uniforms::lightintensity>; using FillExtrusionPatternUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_scale, - uniforms::u_texsize, - uniforms::u_fade, - uniforms::u_pixel_coord_upper, - uniforms::u_pixel_coord_lower, - uniforms::u_height_factor, - uniforms::u_lightcolor, - uniforms::u_lightpos, - uniforms::u_lightintensity>; + uniforms::matrix, + uniforms::scale, + uniforms::texsize, + uniforms::fade, + uniforms::pixel_coord_upper, + uniforms::pixel_coord_lower, + uniforms::height_factor, + uniforms::lightcolor, + uniforms::lightpos, + uniforms::lightintensity>; class FillExtrusionProgram : public Program< FillExtrusionProgram, @@ -91,7 +91,7 @@ class FillExtrusionPatternProgram : public Program< FillExtrusionLayoutAttributes, FillExtrusionPatternUniforms, TypeList< - textures::u_image>, + textures::image>, style::FillExtrusionPaintProperties> { public: @@ -117,8 +117,8 @@ public: : fillExtrusion(context, programParameters), fillExtrusionPattern(context, programParameters), extrusionTexture(context, programParameters) {} - ProgramMap<FillExtrusionProgram> fillExtrusion; - ProgramMap<FillExtrusionPatternProgram> fillExtrusionPattern; + FillExtrusionProgram fillExtrusion; + FillExtrusionPatternProgram fillExtrusionPattern; ExtrusionTextureProgram extrusionTexture; }; diff --git a/src/mbgl/programs/fill_program.cpp b/src/mbgl/programs/fill_program.cpp index e0dfc71f81..703d61399f 100644 --- a/src/mbgl/programs/fill_program.cpp +++ b/src/mbgl/programs/fill_program.cpp @@ -30,13 +30,13 @@ FillPatternProgram::layoutUniformValues(mat4 matrix, int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; return { - uniforms::u_matrix::Value( matrix ), - uniforms::u_world::Value( framebufferSize ), - uniforms::u_texsize::Value( atlasSize ), - uniforms::u_scale::Value({ {pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale} } ), - uniforms::u_fade::Value( crossfade.t ), - uniforms::u_pixel_coord_upper::Value( std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }}), - uniforms::u_pixel_coord_lower::Value( std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} ) + uniforms::matrix::Value( matrix ), + uniforms::world::Value( framebufferSize ), + uniforms::texsize::Value( atlasSize ), + uniforms::scale::Value({ {pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale} } ), + uniforms::fade::Value( crossfade.t ), + uniforms::pixel_coord_upper::Value( std::array<float, 2> {{ float(pixelX >> 16), float(pixelY >> 16) }}), + uniforms::pixel_coord_lower::Value( std::array<float, 2> {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }} ) }; } diff --git a/src/mbgl/programs/fill_program.hpp b/src/mbgl/programs/fill_program.hpp index 8519e482d6..99314c51b0 100644 --- a/src/mbgl/programs/fill_program.hpp +++ b/src/mbgl/programs/fill_program.hpp @@ -21,17 +21,17 @@ template <class> class Faded; using FillLayoutAttributes = PositionOnlyLayoutAttributes; using FillUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_world>; + uniforms::matrix, + uniforms::world>; using FillPatternUniforms = TypeList< - uniforms::u_matrix, - uniforms::u_world, - uniforms::u_texsize, - uniforms::u_scale, - uniforms::u_fade, - uniforms::u_pixel_coord_upper, - uniforms::u_pixel_coord_lower>; + uniforms::matrix, + uniforms::world, + uniforms::texsize, + uniforms::scale, + uniforms::fade, + uniforms::pixel_coord_upper, + uniforms::pixel_coord_lower>; class FillProgram : public Program< FillProgram, @@ -60,7 +60,7 @@ class FillPatternProgram : public Program< FillLayoutAttributes, FillPatternUniforms, TypeList< - textures::u_image>, + textures::image>, style::FillPaintProperties> { public: @@ -93,7 +93,7 @@ class FillOutlinePatternProgram : public Program< FillLayoutAttributes, FillPatternUniforms, TypeList< - textures::u_image>, + textures::image>, style::FillPaintProperties> { public: @@ -110,10 +110,10 @@ public: fillPattern(context, programParameters), fillOutline(context, programParameters), fillOutlinePattern(context, programParameters) {} - ProgramMap<FillProgram> fill; - ProgramMap<FillPatternProgram> fillPattern; - ProgramMap<FillOutlineProgram> fillOutline; - ProgramMap<FillOutlinePatternProgram> fillOutlinePattern; + FillProgram fill; + FillPatternProgram fillPattern; + FillOutlineProgram fillOutline; + FillOutlinePatternProgram fillOutlinePattern; }; } // namespace mbgl diff --git a/src/mbgl/programs/gl/background.cpp b/src/mbgl/programs/gl/background.cpp index da5ea25410..78074d670f 100644 --- a/src/mbgl/programs/gl/background.cpp +++ b/src/mbgl/programs/gl/background.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/background_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<BackgroundProgram> { + static constexpr const char* name = "background"; + static constexpr const uint8_t hash[8] = { 0x2d, 0xef, 0x97, 0xa2, 0xec, 0xb5, 0x67, 0xef }; + static constexpr const auto vertexOffset = 1429; + static constexpr const auto fragmentOffset = 1525; +}; + +constexpr const char* ShaderSource<BackgroundProgram>::name; +constexpr const uint8_t ShaderSource<BackgroundProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<BackgroundProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<BackgroundProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "background", - programs::gl::shaderSource() + 1429, programs::gl::shaderSource() + 1525); + return std::make_unique<gl::Program<BackgroundProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/background_pattern.cpp b/src/mbgl/programs/gl/background_pattern.cpp index af5d87129e..04111c7abd 100644 --- a/src/mbgl/programs/gl/background_pattern.cpp +++ b/src/mbgl/programs/gl/background_pattern.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/background_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<BackgroundPatternProgram> { + static constexpr const char* name = "background_pattern"; + static constexpr const uint8_t hash[8] = { 0x70, 0x13, 0xc8, 0x7e, 0xba, 0x18, 0xf5, 0x19 }; + static constexpr const auto vertexOffset = 1675; + static constexpr const auto fragmentOffset = 2266; +}; + +constexpr const char* ShaderSource<BackgroundPatternProgram>::name; +constexpr const uint8_t ShaderSource<BackgroundPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<BackgroundPatternProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<BackgroundPatternProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "background_pattern", - programs::gl::shaderSource() + 1675, programs::gl::shaderSource() + 2266); + return std::make_unique<gl::Program<BackgroundPatternProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/circle.cpp b/src/mbgl/programs/gl/circle.cpp index 04c3f60870..d1f1e29d33 100644 --- a/src/mbgl/programs/gl/circle.cpp +++ b/src/mbgl/programs/gl/circle.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/circle_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CircleProgram> { + static constexpr const char* name = "circle"; + static constexpr const uint8_t hash[8] = { 0xf0, 0x3e, 0x18, 0xb7, 0x75, 0xb2, 0xde, 0xa9 }; + static constexpr const auto vertexOffset = 2927; + static constexpr const auto fragmentOffset = 6093; +}; + +constexpr const char* ShaderSource<CircleProgram>::name; +constexpr const uint8_t ShaderSource<CircleProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<CircleProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<CircleProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "circle", - programs::gl::shaderSource() + 2927, programs::gl::shaderSource() + 6093); + return std::make_unique<gl::Program<CircleProgram>>(programParameters); } } // namespace gfx @@ -30,7 +49,7 @@ attribute vec2 a_pos; #ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; +uniform lowp float u_color_t; attribute highp vec4 a_color; varying highp vec4 color; #else @@ -39,7 +58,7 @@ uniform highp vec4 u_color; #ifndef HAS_UNIFORM_u_radius -uniform lowp float a_radius_t; +uniform lowp float u_radius_t; attribute mediump vec2 a_radius; varying mediump float radius; #else @@ -48,7 +67,7 @@ uniform mediump float u_radius; #ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; +uniform lowp float u_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; #else @@ -57,7 +76,7 @@ uniform lowp float u_blur; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -66,7 +85,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_stroke_color -uniform lowp float a_stroke_color_t; +uniform lowp float u_stroke_color_t; attribute highp vec4 a_stroke_color; varying highp vec4 stroke_color; #else @@ -75,7 +94,7 @@ uniform highp vec4 u_stroke_color; #ifndef HAS_UNIFORM_u_stroke_width -uniform lowp float a_stroke_width_t; +uniform lowp float u_stroke_width_t; attribute mediump vec2 a_stroke_width; varying mediump float stroke_width; #else @@ -84,7 +103,7 @@ uniform mediump float u_stroke_width; #ifndef HAS_UNIFORM_u_stroke_opacity -uniform lowp float a_stroke_opacity_t; +uniform lowp float u_stroke_opacity_t; attribute lowp vec2 a_stroke_opacity; varying lowp float stroke_opacity; #else @@ -97,49 +116,49 @@ varying vec3 v_data; void main(void) { #ifndef HAS_UNIFORM_u_color - color = unpack_mix_color(a_color, a_color_t); + color = unpack_mix_color(a_color, u_color_t); #else highp vec4 color = u_color; #endif #ifndef HAS_UNIFORM_u_radius - radius = unpack_mix_vec2(a_radius, a_radius_t); + radius = unpack_mix_vec2(a_radius, u_radius_t); #else mediump float radius = u_radius; #endif #ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); + blur = unpack_mix_vec2(a_blur, u_blur_t); #else lowp float blur = u_blur; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_stroke_color - stroke_color = unpack_mix_color(a_stroke_color, a_stroke_color_t); + stroke_color = unpack_mix_color(a_stroke_color, u_stroke_color_t); #else highp vec4 stroke_color = u_stroke_color; #endif #ifndef HAS_UNIFORM_u_stroke_width - stroke_width = unpack_mix_vec2(a_stroke_width, a_stroke_width_t); + stroke_width = unpack_mix_vec2(a_stroke_width, u_stroke_width_t); #else mediump float stroke_width = u_stroke_width; #endif #ifndef HAS_UNIFORM_u_stroke_opacity - stroke_opacity = unpack_mix_vec2(a_stroke_opacity, a_stroke_opacity_t); + stroke_opacity = unpack_mix_vec2(a_stroke_opacity, u_stroke_opacity_t); #else lowp float stroke_opacity = u_stroke_opacity; #endif diff --git a/src/mbgl/programs/gl/clipping_mask.cpp b/src/mbgl/programs/gl/clipping_mask.cpp index 311877f065..3179ab0c13 100644 --- a/src/mbgl/programs/gl/clipping_mask.cpp +++ b/src/mbgl/programs/gl/clipping_mask.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/clipping_mask_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<ClippingMaskProgram> { + static constexpr const char* name = "clipping_mask"; + static constexpr const uint8_t hash[8] = { 0x3e, 0x17, 0xc2, 0x3a, 0x1f, 0xf0, 0xa8, 0xa3 }; + static constexpr const auto vertexOffset = 7848; + static constexpr const auto fragmentOffset = 7944; +}; + +constexpr const char* ShaderSource<ClippingMaskProgram>::name; +constexpr const uint8_t ShaderSource<ClippingMaskProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<ClippingMaskProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<ClippingMaskProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "clipping_mask", - programs::gl::shaderSource() + 7848, programs::gl::shaderSource() + 7944); + return std::make_unique<gl::Program<ClippingMaskProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/collision_box.cpp b/src/mbgl/programs/gl/collision_box.cpp index 9af67f7981..f7ac4d4d67 100644 --- a/src/mbgl/programs/gl/collision_box.cpp +++ b/src/mbgl/programs/gl/collision_box.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/collision_box_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CollisionBoxProgram> { + static constexpr const char* name = "collision_box"; + static constexpr const uint8_t hash[8] = { 0xcb, 0x6a, 0x9b, 0xd1, 0x1f, 0x31, 0xf8, 0x5b }; + static constexpr const auto vertexOffset = 9956; + static constexpr const auto fragmentOffset = 10635; +}; + +constexpr const char* ShaderSource<CollisionBoxProgram>::name; +constexpr const uint8_t ShaderSource<CollisionBoxProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<CollisionBoxProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<CollisionBoxProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "collision_box", - programs::gl::shaderSource() + 9956, programs::gl::shaderSource() + 10635); + return std::make_unique<gl::Program<CollisionBoxProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/collision_circle.cpp b/src/mbgl/programs/gl/collision_circle.cpp index 843f9161bb..8f1b5726fe 100644 --- a/src/mbgl/programs/gl/collision_circle.cpp +++ b/src/mbgl/programs/gl/collision_circle.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/collision_circle_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CollisionCircleProgram> { + static constexpr const char* name = "collision_circle"; + static constexpr const uint8_t hash[8] = { 0x99, 0x2e, 0xad, 0x8c, 0xd3, 0x88, 0xae, 0x82 }; + static constexpr const auto vertexOffset = 10858; + static constexpr const auto fragmentOffset = 11774; +}; + +constexpr const char* ShaderSource<CollisionCircleProgram>::name; +constexpr const uint8_t ShaderSource<CollisionCircleProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<CollisionCircleProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<CollisionCircleProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "collision_circle", - programs::gl::shaderSource() + 10858, programs::gl::shaderSource() + 11774); + return std::make_unique<gl::Program<CollisionCircleProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/debug.cpp b/src/mbgl/programs/gl/debug.cpp index 8b7aee5a0b..ad23f420ab 100644 --- a/src/mbgl/programs/gl/debug.cpp +++ b/src/mbgl/programs/gl/debug.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/debug_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<DebugProgram> { + static constexpr const char* name = "debug"; + static constexpr const uint8_t hash[8] = { 0xa8, 0x7d, 0x87, 0x6e, 0x36, 0xa8, 0x81, 0xe3 }; + static constexpr const auto vertexOffset = 12450; + static constexpr const auto fragmentOffset = 12546; +}; + +constexpr const char* ShaderSource<DebugProgram>::name; +constexpr const uint8_t ShaderSource<DebugProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<DebugProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<DebugProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "debug", - programs::gl::shaderSource() + 12450, programs::gl::shaderSource() + 12546); + return std::make_unique<gl::Program<DebugProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/extrusion_texture.cpp b/src/mbgl/programs/gl/extrusion_texture.cpp index bd320d52cf..bca533a788 100644 --- a/src/mbgl/programs/gl/extrusion_texture.cpp +++ b/src/mbgl/programs/gl/extrusion_texture.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/extrusion_texture_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<ExtrusionTextureProgram> { + static constexpr const char* name = "extrusion_texture"; + static constexpr const uint8_t hash[8] = { 0xd9, 0x77, 0x11, 0xd2, 0x03, 0xc7, 0x27, 0xcb }; + static constexpr const auto vertexOffset = 27554; + static constexpr const auto fragmentOffset = 27734; +}; + +constexpr const char* ShaderSource<ExtrusionTextureProgram>::name; +constexpr const uint8_t ShaderSource<ExtrusionTextureProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<ExtrusionTextureProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<ExtrusionTextureProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "extrusion_texture", - programs::gl::shaderSource() + 27554, programs::gl::shaderSource() + 27734); + return std::make_unique<gl::Program<ExtrusionTextureProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/fill.cpp b/src/mbgl/programs/gl/fill.cpp index c15c2774ab..a699f82609 100644 --- a/src/mbgl/programs/gl/fill.cpp +++ b/src/mbgl/programs/gl/fill.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillProgram> { + static constexpr const char* name = "fill"; + static constexpr const uint8_t hash[8] = { 0x87, 0xea, 0x65, 0x7f, 0x0c, 0x9b, 0x97, 0x5d }; + static constexpr const auto vertexOffset = 12610; + static constexpr const auto fragmentOffset = 13254; +}; + +constexpr const char* ShaderSource<FillProgram>::name; +constexpr const uint8_t ShaderSource<FillProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill", - programs::gl::shaderSource() + 12610, programs::gl::shaderSource() + 13254); + return std::make_unique<gl::Program<FillProgram>>(programParameters); } } // namespace gfx @@ -26,7 +45,7 @@ uniform mat4 u_matrix; #ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; +uniform lowp float u_color_t; attribute highp vec4 a_color; varying highp vec4 color; #else @@ -35,7 +54,7 @@ uniform highp vec4 u_color; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -46,14 +65,14 @@ uniform lowp float u_opacity; void main() { #ifndef HAS_UNIFORM_u_color - color = unpack_mix_color(a_color, a_color_t); + color = unpack_mix_color(a_color, u_color_t); #else highp vec4 color = u_color; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif diff --git a/src/mbgl/programs/gl/fill_extrusion.cpp b/src/mbgl/programs/gl/fill_extrusion.cpp index 45ebb68dd4..83a8eadee6 100644 --- a/src/mbgl/programs/gl/fill_extrusion.cpp +++ b/src/mbgl/programs/gl/fill_extrusion.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillExtrusionProgram> { + static constexpr const char* name = "fill_extrusion"; + static constexpr const uint8_t hash[8] = { 0x49, 0x8a, 0xa2, 0x8b, 0x21, 0x74, 0x27, 0x93 }; + static constexpr const auto vertexOffset = 21238; + static constexpr const auto fragmentOffset = 23121; +}; + +constexpr const char* ShaderSource<FillExtrusionProgram>::name; +constexpr const uint8_t ShaderSource<FillExtrusionProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillExtrusionProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillExtrusionProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill_extrusion", - programs::gl::shaderSource() + 21238, programs::gl::shaderSource() + 23121); + return std::make_unique<gl::Program<FillExtrusionProgram>>(programParameters); } } // namespace gfx @@ -33,7 +52,7 @@ varying vec4 v_color; #ifndef HAS_UNIFORM_u_base -uniform lowp float a_base_t; +uniform lowp float u_base_t; attribute highp vec2 a_base; #else uniform highp float u_base; @@ -41,7 +60,7 @@ uniform highp float u_base; #ifndef HAS_UNIFORM_u_height -uniform lowp float a_height_t; +uniform lowp float u_height_t; attribute highp vec2 a_height; #else uniform highp float u_height; @@ -50,7 +69,7 @@ uniform highp float u_height; #ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; +uniform lowp float u_color_t; attribute highp vec4 a_color; #else uniform highp vec4 u_color; @@ -60,21 +79,21 @@ uniform highp vec4 u_color; void main() { #ifndef HAS_UNIFORM_u_base - highp float base = unpack_mix_vec2(a_base, a_base_t); + highp float base = unpack_mix_vec2(a_base, u_base_t); #else highp float base = u_base; #endif #ifndef HAS_UNIFORM_u_height - highp float height = unpack_mix_vec2(a_height, a_height_t); + highp float height = unpack_mix_vec2(a_height, u_height_t); #else highp float height = u_height; #endif #ifndef HAS_UNIFORM_u_color - highp vec4 color = unpack_mix_color(a_color, a_color_t); + highp vec4 color = unpack_mix_color(a_color, u_color_t); #else highp vec4 color = u_color; #endif diff --git a/src/mbgl/programs/gl/fill_extrusion_pattern.cpp b/src/mbgl/programs/gl/fill_extrusion_pattern.cpp index 9c2da87b11..45068d84b8 100644 --- a/src/mbgl/programs/gl/fill_extrusion_pattern.cpp +++ b/src/mbgl/programs/gl/fill_extrusion_pattern.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_extrusion_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillExtrusionPatternProgram> { + static constexpr const char* name = "fill_extrusion_pattern"; + static constexpr const uint8_t hash[8] = { 0x93, 0x2b, 0xd1, 0xab, 0xa3, 0xf2, 0x24, 0x63 }; + static constexpr const auto vertexOffset = 23237; + static constexpr const auto fragmentOffset = 26157; +}; + +constexpr const char* ShaderSource<FillExtrusionPatternProgram>::name; +constexpr const uint8_t ShaderSource<FillExtrusionPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillExtrusionPatternProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillExtrusionPatternProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill_extrusion_pattern", - programs::gl::shaderSource() + 23237, programs::gl::shaderSource() + 26157); + return std::make_unique<gl::Program<FillExtrusionPatternProgram>>(programParameters); } } // namespace gfx @@ -40,7 +59,7 @@ varying vec4 v_lighting; #ifndef HAS_UNIFORM_u_base -uniform lowp float a_base_t; +uniform lowp float u_base_t; attribute lowp vec2 a_base; varying lowp float base; #else @@ -49,7 +68,7 @@ uniform lowp float u_base; #ifndef HAS_UNIFORM_u_height -uniform lowp float a_height_t; +uniform lowp float u_height_t; attribute lowp vec2 a_height; varying lowp float height; #else @@ -58,7 +77,7 @@ uniform lowp float u_height; #ifndef HAS_UNIFORM_u_pattern_from -uniform lowp float a_pattern_from_t; +uniform lowp float u_pattern_from_t; attribute lowp vec4 a_pattern_from; varying lowp vec4 pattern_from; #else @@ -67,7 +86,7 @@ uniform lowp vec4 u_pattern_from; #ifndef HAS_UNIFORM_u_pattern_to -uniform lowp float a_pattern_to_t; +uniform lowp float u_pattern_to_t; attribute lowp vec4 a_pattern_to; varying lowp vec4 pattern_to; #else @@ -78,14 +97,14 @@ uniform lowp vec4 u_pattern_to; void main() { #ifndef HAS_UNIFORM_u_base - base = unpack_mix_vec2(a_base, a_base_t); + base = unpack_mix_vec2(a_base, u_base_t); #else lowp float base = u_base; #endif #ifndef HAS_UNIFORM_u_height - height = unpack_mix_vec2(a_height, a_height_t); + height = unpack_mix_vec2(a_height, u_height_t); #else lowp float height = u_height; #endif diff --git a/src/mbgl/programs/gl/fill_outline.cpp b/src/mbgl/programs/gl/fill_outline.cpp index 07615b2138..e7644468a5 100644 --- a/src/mbgl/programs/gl/fill_outline.cpp +++ b/src/mbgl/programs/gl/fill_outline.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_outline_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillOutlineProgram> { + static constexpr const char* name = "fill_outline"; + static constexpr const uint8_t hash[8] = { 0x56, 0x65, 0x69, 0x4b, 0x70, 0x2d, 0x3d, 0xc4 }; + static constexpr const auto vertexOffset = 13678; + static constexpr const auto fragmentOffset = 14503; +}; + +constexpr const char* ShaderSource<FillOutlineProgram>::name; +constexpr const uint8_t ShaderSource<FillOutlineProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillOutlineProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillOutlineProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill_outline", - programs::gl::shaderSource() + 13678, programs::gl::shaderSource() + 14503); + return std::make_unique<gl::Program<FillOutlineProgram>>(programParameters); } } // namespace gfx @@ -29,7 +48,7 @@ varying vec2 v_pos; #ifndef HAS_UNIFORM_u_outline_color -uniform lowp float a_outline_color_t; +uniform lowp float u_outline_color_t; attribute highp vec4 a_outline_color; varying highp vec4 outline_color; #else @@ -38,7 +57,7 @@ uniform highp vec4 u_outline_color; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -49,14 +68,14 @@ uniform lowp float u_opacity; void main() { #ifndef HAS_UNIFORM_u_outline_color - outline_color = unpack_mix_color(a_outline_color, a_outline_color_t); + outline_color = unpack_mix_color(a_outline_color, u_outline_color_t); #else highp vec4 outline_color = u_outline_color; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif diff --git a/src/mbgl/programs/gl/fill_outline_pattern.cpp b/src/mbgl/programs/gl/fill_outline_pattern.cpp index 7e0bf19655..40aa5ea2de 100644 --- a/src/mbgl/programs/gl/fill_outline_pattern.cpp +++ b/src/mbgl/programs/gl/fill_outline_pattern.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_outline_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillOutlinePatternProgram> { + static constexpr const char* name = "fill_outline_pattern"; + static constexpr const uint8_t hash[8] = { 0x56, 0x9c, 0x2f, 0x58, 0x6b, 0x31, 0xff, 0x84 }; + static constexpr const auto vertexOffset = 15092; + static constexpr const auto fragmentOffset = 16952; +}; + +constexpr const char* ShaderSource<FillOutlinePatternProgram>::name; +constexpr const uint8_t ShaderSource<FillOutlinePatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillOutlinePatternProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillOutlinePatternProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill_outline_pattern", - programs::gl::shaderSource() + 15092, programs::gl::shaderSource() + 16952); + return std::make_unique<gl::Program<FillOutlinePatternProgram>>(programParameters); } } // namespace gfx @@ -34,7 +53,7 @@ varying vec2 v_pos; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -43,7 +62,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_pattern_from -uniform lowp float a_pattern_from_t; +uniform lowp float u_pattern_from_t; attribute lowp vec4 a_pattern_from; varying lowp vec4 pattern_from; #else @@ -52,7 +71,7 @@ uniform lowp vec4 u_pattern_from; #ifndef HAS_UNIFORM_u_pattern_to -uniform lowp float a_pattern_to_t; +uniform lowp float u_pattern_to_t; attribute lowp vec4 a_pattern_to; varying lowp vec4 pattern_to; #else @@ -63,7 +82,7 @@ uniform lowp vec4 u_pattern_to; void main() { #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif diff --git a/src/mbgl/programs/gl/fill_pattern.cpp b/src/mbgl/programs/gl/fill_pattern.cpp index 256b1ede99..fd16d8bfc9 100644 --- a/src/mbgl/programs/gl/fill_pattern.cpp +++ b/src/mbgl/programs/gl/fill_pattern.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/fill_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillPatternProgram> { + static constexpr const char* name = "fill_pattern"; + static constexpr const uint8_t hash[8] = { 0x74, 0xa9, 0x97, 0x01, 0x96, 0xbd, 0x87, 0x36 }; + static constexpr const auto vertexOffset = 18259; + static constexpr const auto fragmentOffset = 20038; +}; + +constexpr const char* ShaderSource<FillPatternProgram>::name; +constexpr const uint8_t ShaderSource<FillPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<FillPatternProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<FillPatternProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "fill_pattern", - programs::gl::shaderSource() + 18259, programs::gl::shaderSource() + 20038); + return std::make_unique<gl::Program<FillPatternProgram>>(programParameters); } } // namespace gfx @@ -32,7 +51,7 @@ varying vec2 v_pos_b; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -41,7 +60,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_pattern_from -uniform lowp float a_pattern_from_t; +uniform lowp float u_pattern_from_t; attribute lowp vec4 a_pattern_from; varying lowp vec4 pattern_from; #else @@ -50,7 +69,7 @@ uniform lowp vec4 u_pattern_from; #ifndef HAS_UNIFORM_u_pattern_to -uniform lowp float a_pattern_to_t; +uniform lowp float u_pattern_to_t; attribute lowp vec4 a_pattern_to; varying lowp vec4 pattern_to; #else @@ -61,7 +80,7 @@ uniform lowp vec4 u_pattern_to; void main() { #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif diff --git a/src/mbgl/programs/gl/heatmap.cpp b/src/mbgl/programs/gl/heatmap.cpp index 59f8ad9f69..3b960f1bda 100644 --- a/src/mbgl/programs/gl/heatmap.cpp +++ b/src/mbgl/programs/gl/heatmap.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HeatmapProgram> { + static constexpr const char* name = "heatmap"; + static constexpr const uint8_t hash[8] = { 0xab, 0x97, 0x81, 0x5c, 0xa2, 0x88, 0xaa, 0x7e }; + static constexpr const auto vertexOffset = 7983; + static constexpr const auto fragmentOffset = 9030; +}; + +constexpr const char* ShaderSource<HeatmapProgram>::name; +constexpr const uint8_t ShaderSource<HeatmapProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<HeatmapProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<HeatmapProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "heatmap", - programs::gl::shaderSource() + 7983, programs::gl::shaderSource() + 9030); + return std::make_unique<gl::Program<HeatmapProgram>>(programParameters); } } // namespace gfx @@ -22,7 +41,7 @@ Context::createProgram<gl::Context>(const ProgramParameters& programParameters) /* #ifndef HAS_UNIFORM_u_weight -uniform lowp float a_weight_t; +uniform lowp float u_weight_t; attribute highp vec2 a_weight; varying highp float weight; #else @@ -31,7 +50,7 @@ uniform highp float u_weight; #ifndef HAS_UNIFORM_u_radius -uniform lowp float a_radius_t; +uniform lowp float u_radius_t; attribute mediump vec2 a_radius; #else uniform mediump float u_radius; @@ -58,14 +77,14 @@ const highp float ZERO = 1.0 / 255.0 / 16.0; void main(void) { #ifndef HAS_UNIFORM_u_weight - weight = unpack_mix_vec2(a_weight, a_weight_t); + weight = unpack_mix_vec2(a_weight, u_weight_t); #else highp float weight = u_weight; #endif #ifndef HAS_UNIFORM_u_radius - mediump float radius = unpack_mix_vec2(a_radius, a_radius_t); + mediump float radius = unpack_mix_vec2(a_radius, u_radius_t); #else mediump float radius = u_radius; #endif diff --git a/src/mbgl/programs/gl/heatmap_texture.cpp b/src/mbgl/programs/gl/heatmap_texture.cpp index 530e9fa18b..57b033d55c 100644 --- a/src/mbgl/programs/gl/heatmap_texture.cpp +++ b/src/mbgl/programs/gl/heatmap_texture.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/heatmap_texture_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HeatmapTextureProgram> { + static constexpr const char* name = "heatmap_texture"; + static constexpr const uint8_t hash[8] = { 0x9f, 0xc7, 0x56, 0xb2, 0x9e, 0x8f, 0x15, 0xff }; + static constexpr const auto vertexOffset = 9491; + static constexpr const auto fragmentOffset = 9671; +}; + +constexpr const char* ShaderSource<HeatmapTextureProgram>::name; +constexpr const uint8_t ShaderSource<HeatmapTextureProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<HeatmapTextureProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<HeatmapTextureProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "heatmap_texture", - programs::gl::shaderSource() + 9491, programs::gl::shaderSource() + 9671); + return std::make_unique<gl::Program<HeatmapTextureProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/hillshade.cpp b/src/mbgl/programs/gl/hillshade.cpp index dcf90f1149..a33ddb4326 100644 --- a/src/mbgl/programs/gl/hillshade.cpp +++ b/src/mbgl/programs/gl/hillshade.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/hillshade_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HillshadeProgram> { + static constexpr const char* name = "hillshade"; + static constexpr const uint8_t hash[8] = { 0x8a, 0x11, 0x29, 0x18, 0x52, 0x7f, 0x3b, 0xbb }; + static constexpr const auto vertexOffset = 29340; + static constexpr const auto fragmentOffset = 29511; +}; + +constexpr const char* ShaderSource<HillshadeProgram>::name; +constexpr const uint8_t ShaderSource<HillshadeProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<HillshadeProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<HillshadeProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "hillshade", - programs::gl::shaderSource() + 29340, programs::gl::shaderSource() + 29511); + return std::make_unique<gl::Program<HillshadeProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/hillshade_prepare.cpp b/src/mbgl/programs/gl/hillshade_prepare.cpp index b445713530..a302db5feb 100644 --- a/src/mbgl/programs/gl/hillshade_prepare.cpp +++ b/src/mbgl/programs/gl/hillshade_prepare.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/hillshade_prepare_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HillshadePrepareProgram> { + static constexpr const char* name = "hillshade_prepare"; + static constexpr const uint8_t hash[8] = { 0xe6, 0x01, 0xf2, 0xbb, 0xa0, 0x77, 0x1d, 0xeb }; + static constexpr const auto vertexOffset = 27925; + static constexpr const auto fragmentOffset = 28218; +}; + +constexpr const char* ShaderSource<HillshadePrepareProgram>::name; +constexpr const uint8_t ShaderSource<HillshadePrepareProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<HillshadePrepareProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<HillshadePrepareProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "hillshade_prepare", - programs::gl::shaderSource() + 27925, programs::gl::shaderSource() + 28218); + return std::make_unique<gl::Program<HillshadePrepareProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/line.cpp b/src/mbgl/programs/gl/line.cpp index c25679ae1f..e59cb07cb9 100644 --- a/src/mbgl/programs/gl/line.cpp +++ b/src/mbgl/programs/gl/line.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/line_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineProgram> { + static constexpr const char* name = "line"; + static constexpr const uint8_t hash[8] = { 0x44, 0x46, 0x9e, 0x59, 0x02, 0xbb, 0xaa, 0xae }; + static constexpr const auto vertexOffset = 30585; + static constexpr const auto fragmentOffset = 33509; +}; + +constexpr const char* ShaderSource<LineProgram>::name; +constexpr const uint8_t ShaderSource<LineProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<LineProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<LineProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "line", - programs::gl::shaderSource() + 30585, programs::gl::shaderSource() + 33509); + return std::make_unique<gl::Program<LineProgram>>(programParameters); } } // namespace gfx @@ -48,7 +67,7 @@ varying highp float v_linesofar; #ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; +uniform lowp float u_color_t; attribute highp vec4 a_color; varying highp vec4 color; #else @@ -57,7 +76,7 @@ uniform highp vec4 u_color; #ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; +uniform lowp float u_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; #else @@ -66,7 +85,7 @@ uniform lowp float u_blur; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -75,7 +94,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; +uniform lowp float u_gapwidth_t; attribute mediump vec2 a_gapwidth; #else uniform mediump float u_gapwidth; @@ -83,7 +102,7 @@ uniform mediump float u_gapwidth; #ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; +uniform lowp float u_offset_t; attribute lowp vec2 a_offset; #else uniform lowp float u_offset; @@ -91,7 +110,7 @@ uniform lowp float u_offset; #ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; +uniform lowp float u_width_t; attribute mediump vec2 a_width; #else uniform mediump float u_width; @@ -101,42 +120,42 @@ uniform mediump float u_width; void main() { #ifndef HAS_UNIFORM_u_color - color = unpack_mix_color(a_color, a_color_t); + color = unpack_mix_color(a_color, u_color_t); #else highp vec4 color = u_color; #endif #ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); + blur = unpack_mix_vec2(a_blur, u_blur_t); #else lowp float blur = u_blur; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif #ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); #else lowp float offset = u_offset; #endif #ifndef HAS_UNIFORM_u_width - mediump float width = unpack_mix_vec2(a_width, a_width_t); + mediump float width = unpack_mix_vec2(a_width, u_width_t); #else mediump float width = u_width; #endif diff --git a/src/mbgl/programs/gl/line_gradient.cpp b/src/mbgl/programs/gl/line_gradient.cpp index fae94b4596..f5325f84ba 100644 --- a/src/mbgl/programs/gl/line_gradient.cpp +++ b/src/mbgl/programs/gl/line_gradient.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/line_gradient_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineGradientProgram> { + static constexpr const char* name = "line_gradient"; + static constexpr const uint8_t hash[8] = { 0xee, 0xdd, 0x10, 0x3d, 0x1a, 0x21, 0x26, 0x25 }; + static constexpr const auto vertexOffset = 34335; + static constexpr const auto fragmentOffset = 37054; +}; + +constexpr const char* ShaderSource<LineGradientProgram>::name; +constexpr const uint8_t ShaderSource<LineGradientProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<LineGradientProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<LineGradientProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "line_gradient", - programs::gl::shaderSource() + 34335, programs::gl::shaderSource() + 37054); + return std::make_unique<gl::Program<LineGradientProgram>>(programParameters); } } // namespace gfx @@ -50,7 +69,7 @@ varying highp float v_lineprogress; #ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; +uniform lowp float u_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; #else @@ -59,7 +78,7 @@ uniform lowp float u_blur; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -68,7 +87,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; +uniform lowp float u_gapwidth_t; attribute mediump vec2 a_gapwidth; #else uniform mediump float u_gapwidth; @@ -76,7 +95,7 @@ uniform mediump float u_gapwidth; #ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; +uniform lowp float u_offset_t; attribute lowp vec2 a_offset; #else uniform lowp float u_offset; @@ -84,7 +103,7 @@ uniform lowp float u_offset; #ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; +uniform lowp float u_width_t; attribute mediump vec2 a_width; #else uniform mediump float u_width; @@ -94,35 +113,35 @@ uniform mediump float u_width; void main() { #ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); + blur = unpack_mix_vec2(a_blur, u_blur_t); #else lowp float blur = u_blur; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif #ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); #else lowp float offset = u_offset; #endif #ifndef HAS_UNIFORM_u_width - mediump float width = unpack_mix_vec2(a_width, a_width_t); + mediump float width = unpack_mix_vec2(a_width, u_width_t); #else mediump float width = u_width; #endif diff --git a/src/mbgl/programs/gl/line_pattern.cpp b/src/mbgl/programs/gl/line_pattern.cpp index 2e9ebaf5ea..e323b16785 100644 --- a/src/mbgl/programs/gl/line_pattern.cpp +++ b/src/mbgl/programs/gl/line_pattern.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/line_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LinePatternProgram> { + static constexpr const char* name = "line_pattern"; + static constexpr const uint8_t hash[8] = { 0x73, 0xa0, 0x59, 0x46, 0x57, 0xa5, 0x60, 0x25 }; + static constexpr const auto vertexOffset = 37841; + static constexpr const auto fragmentOffset = 41162; +}; + +constexpr const char* ShaderSource<LinePatternProgram>::name; +constexpr const uint8_t ShaderSource<LinePatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<LinePatternProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<LinePatternProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "line_pattern", - programs::gl::shaderSource() + 37841, programs::gl::shaderSource() + 41162); + return std::make_unique<gl::Program<LinePatternProgram>>(programParameters); } } // namespace gfx @@ -50,7 +69,7 @@ varying float v_gamma_scale; #ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; +uniform lowp float u_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; #else @@ -59,7 +78,7 @@ uniform lowp float u_blur; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -68,7 +87,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; +uniform lowp float u_offset_t; attribute lowp vec2 a_offset; #else uniform lowp float u_offset; @@ -76,7 +95,7 @@ uniform lowp float u_offset; #ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; +uniform lowp float u_gapwidth_t; attribute mediump vec2 a_gapwidth; #else uniform mediump float u_gapwidth; @@ -84,7 +103,7 @@ uniform mediump float u_gapwidth; #ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; +uniform lowp float u_width_t; attribute mediump vec2 a_width; #else uniform mediump float u_width; @@ -92,7 +111,7 @@ uniform mediump float u_width; #ifndef HAS_UNIFORM_u_pattern_from -uniform lowp float a_pattern_from_t; +uniform lowp float u_pattern_from_t; attribute lowp vec4 a_pattern_from; varying lowp vec4 pattern_from; #else @@ -101,7 +120,7 @@ uniform lowp vec4 u_pattern_from; #ifndef HAS_UNIFORM_u_pattern_to -uniform lowp float a_pattern_to_t; +uniform lowp float u_pattern_to_t; attribute lowp vec4 a_pattern_to; varying lowp vec4 pattern_to; #else @@ -112,35 +131,35 @@ uniform lowp vec4 u_pattern_to; void main() { #ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); + blur = unpack_mix_vec2(a_blur, u_blur_t); #else lowp float blur = u_blur; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); #else lowp float offset = u_offset; #endif #ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif #ifndef HAS_UNIFORM_u_width - mediump float width = unpack_mix_vec2(a_width, a_width_t); + mediump float width = unpack_mix_vec2(a_width, u_width_t); #else mediump float width = u_width; #endif diff --git a/src/mbgl/programs/gl/line_sdf.cpp b/src/mbgl/programs/gl/line_sdf.cpp index 0886bfcdf0..a7b4e7e3b7 100644 --- a/src/mbgl/programs/gl/line_sdf.cpp +++ b/src/mbgl/programs/gl/line_sdf.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/line_sdf_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineSDFProgram> { + static constexpr const char* name = "line_sdf"; + static constexpr const uint8_t hash[8] = { 0x66, 0x20, 0x75, 0x4e, 0xbe, 0x02, 0x9e, 0x67 }; + static constexpr const auto vertexOffset = 43475; + static constexpr const auto fragmentOffset = 47089; +}; + +constexpr const char* ShaderSource<LineSDFProgram>::name; +constexpr const uint8_t ShaderSource<LineSDFProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<LineSDFProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<LineSDFProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "line_sdf", - programs::gl::shaderSource() + 43475, programs::gl::shaderSource() + 47089); + return std::make_unique<gl::Program<LineSDFProgram>>(programParameters); } } // namespace gfx @@ -55,7 +74,7 @@ varying float v_gamma_scale; #ifndef HAS_UNIFORM_u_color -uniform lowp float a_color_t; +uniform lowp float u_color_t; attribute highp vec4 a_color; varying highp vec4 color; #else @@ -64,7 +83,7 @@ uniform highp vec4 u_color; #ifndef HAS_UNIFORM_u_blur -uniform lowp float a_blur_t; +uniform lowp float u_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; #else @@ -73,7 +92,7 @@ uniform lowp float u_blur; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -82,7 +101,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_gapwidth -uniform lowp float a_gapwidth_t; +uniform lowp float u_gapwidth_t; attribute mediump vec2 a_gapwidth; #else uniform mediump float u_gapwidth; @@ -90,7 +109,7 @@ uniform mediump float u_gapwidth; #ifndef HAS_UNIFORM_u_offset -uniform lowp float a_offset_t; +uniform lowp float u_offset_t; attribute lowp vec2 a_offset; #else uniform lowp float u_offset; @@ -98,7 +117,7 @@ uniform lowp float u_offset; #ifndef HAS_UNIFORM_u_width -uniform lowp float a_width_t; +uniform lowp float u_width_t; attribute mediump vec2 a_width; varying mediump float width; #else @@ -107,7 +126,7 @@ uniform mediump float u_width; #ifndef HAS_UNIFORM_u_floorwidth -uniform lowp float a_floorwidth_t; +uniform lowp float u_floorwidth_t; attribute lowp vec2 a_floorwidth; varying lowp float floorwidth; #else @@ -118,49 +137,49 @@ uniform lowp float u_floorwidth; void main() { #ifndef HAS_UNIFORM_u_color - color = unpack_mix_color(a_color, a_color_t); + color = unpack_mix_color(a_color, u_color_t); #else highp vec4 color = u_color; #endif #ifndef HAS_UNIFORM_u_blur - blur = unpack_mix_vec2(a_blur, a_blur_t); + blur = unpack_mix_vec2(a_blur, u_blur_t); #else lowp float blur = u_blur; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_gapwidth - mediump float gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t); + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); #else mediump float gapwidth = u_gapwidth; #endif #ifndef HAS_UNIFORM_u_offset - lowp float offset = unpack_mix_vec2(a_offset, a_offset_t); + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); #else lowp float offset = u_offset; #endif #ifndef HAS_UNIFORM_u_width - width = unpack_mix_vec2(a_width, a_width_t); + width = unpack_mix_vec2(a_width, u_width_t); #else mediump float width = u_width; #endif #ifndef HAS_UNIFORM_u_floorwidth - floorwidth = unpack_mix_vec2(a_floorwidth, a_floorwidth_t); + floorwidth = unpack_mix_vec2(a_floorwidth, u_floorwidth_t); #else lowp float floorwidth = u_floorwidth; #endif diff --git a/src/mbgl/programs/gl/preludes.cpp b/src/mbgl/programs/gl/preludes.cpp deleted file mode 100644 index 6c895c0d36..0000000000 --- a/src/mbgl/programs/gl/preludes.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. - -#include <mbgl/programs/gl/preludes.hpp> -#include <mbgl/programs/gl/shader_source.hpp> - -namespace mbgl { -namespace programs { -namespace gl { - -const char* vertexShaderPrelude = programs::gl::shaderSource() + 0; -const char* fragmentShaderPrelude = programs::gl::shaderSource() + 1252; - -} // namespace gl -} // namespace programs -} // namespace mbgl diff --git a/src/mbgl/programs/gl/preludes.hpp b/src/mbgl/programs/gl/preludes.hpp index 6d86ee45c5..e796f1655b 100644 --- a/src/mbgl/programs/gl/preludes.hpp +++ b/src/mbgl/programs/gl/preludes.hpp @@ -2,12 +2,15 @@ #pragma once +#include <cstdint> + namespace mbgl { namespace programs { namespace gl { -extern const char* vertexShaderPrelude; -extern const char* fragmentShaderPrelude; +constexpr const uint8_t preludeHash[8] = { 0x24, 0x91, 0x82, 0x37, 0x02, 0xad, 0x98, 0x0a }; +constexpr const auto vertexPreludeOffset = 0; +constexpr const auto fragmentPreludeOffset = 1252; } // namespace gl } // namespace programs diff --git a/src/mbgl/programs/gl/raster.cpp b/src/mbgl/programs/gl/raster.cpp index 512dc81a30..1867a48f1c 100644 --- a/src/mbgl/programs/gl/raster.cpp +++ b/src/mbgl/programs/gl/raster.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/raster_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<RasterProgram> { + static constexpr const char* name = "raster"; + static constexpr const uint8_t hash[8] = { 0x40, 0x3d, 0x6c, 0xf4, 0xd0, 0x41, 0x51, 0x0e }; + static constexpr const auto vertexOffset = 48592; + static constexpr const auto fragmentOffset = 48941; +}; + +constexpr const char* ShaderSource<RasterProgram>::name; +constexpr const uint8_t ShaderSource<RasterProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<RasterProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<RasterProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "raster", - programs::gl::shaderSource() + 48592, programs::gl::shaderSource() + 48941); + return std::make_unique<gl::Program<RasterProgram>>(programParameters); } } // namespace gfx diff --git a/src/mbgl/programs/gl/shader_source.cpp b/src/mbgl/programs/gl/shader_source.cpp index 4a986403f7..00e70f749a 100644 --- a/src/mbgl/programs/gl/shader_source.cpp +++ b/src/mbgl/programs/gl/shader_source.cpp @@ -70,395 +70,395 @@ constexpr const uint8_t compressedShaderSource[] = { 0x3a, 0x0f, 0xf2, 0x3e, 0x9e, 0xa4, 0xf3, 0x18, 0x26, 0x4d, 0x2f, 0x9d, 0xa2, 0x4e, 0xec, 0xf6, 0x47, 0x8b, 0x3c, 0x9e, 0xf6, 0x52, 0xb3, 0x64, 0x82, 0x06, 0x4f, 0xa1, 0xc5, 0xff, 0x7d, 0x72, 0xd1, 0xfd, 0xfd, 0xcb, 0xd9, 0xe7, 0xaf, 0xdf, 0x7e, 0xed, 0x52, 0xd9, 0x7f, 0xc0, 0x6a, 0x80, - 0xc5, 0x91, 0x56, 0x10, 0x93, 0xac, 0x6e, 0x2e, 0xa1, 0x23, 0x04, 0xe0, 0xe1, 0xa0, 0xd9, 0x9c, - 0x7b, 0xa5, 0x2c, 0x92, 0x41, 0x57, 0x62, 0x95, 0x76, 0x65, 0xa9, 0x92, 0x16, 0x56, 0x03, 0x61, - 0xf3, 0x18, 0xad, 0xbe, 0x0b, 0x33, 0x65, 0x24, 0x4f, 0x21, 0x8d, 0xa9, 0x01, 0xb4, 0xc5, 0x04, - 0x82, 0x53, 0xa7, 0x28, 0x09, 0x35, 0x9a, 0xa9, 0x51, 0xa8, 0xc2, 0x30, 0x02, 0xd6, 0x50, 0x99, - 0x8c, 0xaf, 0x2c, 0xbd, 0x07, 0x39, 0x0a, 0x85, 0x38, 0x97, 0x92, 0x07, 0x99, 0x9c, 0x38, 0xa9, - 0x18, 0x4e, 0xd7, 0xe8, 0x92, 0xb2, 0x49, 0x7d, 0x6b, 0x48, 0xa2, 0x1c, 0x6e, 0xa6, 0x8a, 0x66, - 0x5a, 0x09, 0xe3, 0xea, 0x42, 0x91, 0x36, 0x31, 0x73, 0xec, 0xe4, 0x49, 0x30, 0x25, 0x14, 0x2e, - 0xf2, 0x79, 0xf6, 0xef, 0xb4, 0x8c, 0xf5, 0x64, 0x08, 0x3b, 0x07, 0xca, 0x50, 0x26, 0x46, 0x54, - 0xf2, 0xcb, 0xf8, 0x51, 0x07, 0x5c, 0x4f, 0xfb, 0xcd, 0xa8, 0x9f, 0x0f, 0x4b, 0x69, 0xc7, 0x10, - 0x65, 0x2c, 0x2a, 0xc3, 0x59, 0x18, 0x55, 0x01, 0x59, 0xc3, 0xae, 0x3a, 0xec, 0xfa, 0x36, 0x94, - 0x32, 0x8a, 0x0a, 0x63, 0xe5, 0x17, 0x15, 0xcc, 0xc4, 0x36, 0x1a, 0x44, 0x19, 0xf7, 0x14, 0x41, - 0x89, 0xbb, 0x40, 0x2c, 0x90, 0x87, 0x68, 0x81, 0xec, 0xc7, 0x79, 0x2c, 0xad, 0x8f, 0xf0, 0x0b, - 0xad, 0x91, 0xa5, 0xe2, 0xad, 0x47, 0x14, 0x5d, 0xdd, 0xc4, 0xa4, 0x32, 0xcc, 0xe7, 0xa2, 0xce, - 0x65, 0xe4, 0xe9, 0xd2, 0x2c, 0xda, 0x48, 0x66, 0x91, 0x3f, 0x91, 0x6e, 0x3b, 0x33, 0xa9, 0xe4, - 0x0b, 0x01, 0xc6, 0x2b, 0x34, 0x09, 0xa8, 0x68, 0x13, 0x19, 0x04, 0xff, 0x18, 0x6a, 0x84, 0x64, - 0x9f, 0x09, 0x23, 0x5e, 0x9b, 0x26, 0x71, 0xa2, 0x8d, 0xe4, 0x0a, 0xfd, 0x6b, 0xa8, 0x8c, 0xe6, - 0xf8, 0x92, 0x98, 0x31, 0x55, 0xc9, 0x11, 0x6c, 0x23, 0x2e, 0xe4, 0x0f, 0xd3, 0x88, 0xca, 0xf9, - 0xbe, 0x2e, 0x48, 0x4c, 0xe3, 0xab, 0x22, 0xdc, 0x5a, 0x14, 0xc8, 0x1f, 0x86, 0xae, 0x91, 0xb3, - 0x7d, 0x5d, 0x46, 0x58, 0xb8, 0x40, 0x45, 0x79, 0x8f, 0x09, 0xae, 0x7e, 0xda, 0xa9, 0x13, 0xe3, - 0xa7, 0xcf, 0x7e, 0xd3, 0x30, 0xea, 0x58, 0xad, 0xd3, 0x17, 0xfb, 0xac, 0x88, 0x42, 0x13, 0xe1, - 0x0a, 0x41, 0x5d, 0x24, 0x76, 0x0d, 0xb8, 0xbb, 0x3c, 0xf4, 0x4f, 0x43, 0x68, 0x8d, 0xbd, 0xd1, - 0xbc, 0x87, 0xf4, 0x26, 0xa2, 0xd3, 0x44, 0xa8, 0x2a, 0x3c, 0xac, 0x08, 0xd8, 0x6b, 0x35, 0x8f, - 0xdd, 0x10, 0x19, 0xe1, 0x8e, 0xae, 0x3d, 0x31, 0x15, 0xb9, 0x97, 0xcd, 0xa7, 0x48, 0x0f, 0x9a, - 0x31, 0x4b, 0x4a, 0x41, 0x45, 0x4b, 0xaa, 0x5a, 0x19, 0x2a, 0xa9, 0x15, 0xaa, 0x47, 0x94, 0x54, - 0xcf, 0x21, 0x93, 0xaf, 0x2e, 0xf7, 0x3b, 0x68, 0x90, 0xaa, 0x6e, 0x76, 0x57, 0x83, 0x7e, 0xa1, - 0x6e, 0xa8, 0xd9, 0x3c, 0xfb, 0x57, 0xda, 0xcb, 0xd3, 0x3e, 0x23, 0x5f, 0xb5, 0xe5, 0x14, 0x7a, - 0x88, 0x4d, 0x77, 0xbf, 0xda, 0x3d, 0x47, 0xaf, 0xb1, 0x79, 0x13, 0x94, 0x68, 0x86, 0xc8, 0xa2, - 0xb2, 0x5b, 0x9a, 0x1a, 0x29, 0xd4, 0xcd, 0x40, 0x9b, 0x57, 0x52, 0xac, 0xd8, 0x28, 0x4b, 0x4f, - 0x4b, 0x38, 0x9a, 0xcb, 0xd5, 0xa6, 0x4d, 0x2d, 0x53, 0x78, 0x0d, 0x54, 0x6e, 0x51, 0x83, 0x5c, - 0xfa, 0x26, 0xbc, 0xbb, 0x93, 0xd7, 0xc3, 0x69, 0x3e, 0x8a, 0xc7, 0xa3, 0x78, 0x81, 0xc5, 0x25, - 0x62, 0xd6, 0xe0, 0xd3, 0xe9, 0x1f, 0x67, 0x1f, 0x4f, 0xbb, 0xe7, 0x67, 0x7f, 0x9e, 0xfe, 0xd2, - 0xfd, 0x76, 0xf2, 0xdb, 0xd9, 0xd7, 0xc0, 0x58, 0x4b, 0x48, 0x16, 0x2c, 0x60, 0xfc, 0x43, 0x87, - 0xd6, 0xd7, 0x5c, 0xfa, 0xec, 0x17, 0x9a, 0x6c, 0x32, 0x6a, 0x97, 0x3a, 0xba, 0xac, 0x2b, 0xd9, - 0x63, 0xab, 0xdb, 0xbb, 0x51, 0x98, 0x1f, 0x59, 0xf3, 0xdd, 0x9d, 0xf2, 0xfa, 0x14, 0x4a, 0xe7, - 0x53, 0xaa, 0x8a, 0x4f, 0xa0, 0xdf, 0x51, 0xdd, 0xce, 0x36, 0x21, 0xaa, 0x68, 0x6a, 0x56, 0x6e, - 0xaf, 0xac, 0x75, 0x59, 0xf8, 0x78, 0xbd, 0x1e, 0x65, 0x67, 0xd2, 0xaa, 0x0a, 0xd1, 0x1a, 0x0e, - 0xdc, 0x5c, 0x93, 0x59, 0xc3, 0x5e, 0x5b, 0xe9, 0x20, 0x6b, 0x19, 0xe7, 0xde, 0x7a, 0x03, 0x66, - 0x0b, 0x24, 0xd4, 0x43, 0x82, 0x84, 0x49, 0xee, 0x71, 0x3a, 0x1d, 0x20, 0xca, 0xc8, 0x1f, 0x26, - 0x5f, 0xdd, 0xd0, 0x2a, 0xba, 0x29, 0x9e, 0xdb, 0x50, 0xcb, 0x44, 0x0b, 0x28, 0xce, 0x6f, 0x4c, - 0xe2, 0xa5, 0x43, 0x94, 0x66, 0x55, 0x2e, 0x2b, 0x23, 0xd5, 0xcd, 0xa3, 0xc5, 0x24, 0xcb, 0xf2, - 0xe1, 0x22, 0x4f, 0x67, 0x4e, 0xab, 0xd9, 0xf2, 0x75, 0x44, 0xbe, 0x4a, 0x20, 0xd1, 0x6f, 0x08, - 0x0e, 0xaa, 0x8b, 0x46, 0x72, 0x5f, 0xd6, 0xfe, 0x51, 0x43, 0x58, 0xda, 0xb5, 0x9f, 0xe0, 0x4f, - 0xed, 0x43, 0x4d, 0xc2, 0x5e, 0xc0, 0x0c, 0xd5, 0x69, 0xd8, 0x09, 0xc3, 0x9a, 0x17, 0x20, 0xcd, - 0x35, 0xc6, 0x5b, 0xe0, 0x71, 0x27, 0x99, 0xc7, 0xf4, 0x3e, 0x99, 0x63, 0x3c, 0x4d, 0x27, 0x94, - 0x34, 0xe8, 0x7b, 0x38, 0xce, 0x1e, 0x7b, 0x4b, 0xc4, 0xbe, 0xcb, 0x21, 0xc8, 0xb1, 0xae, 0xb0, - 0x37, 0x29, 0x9a, 0x4b, 0xb9, 0xd9, 0x1c, 0x26, 0x79, 0x66, 0x57, 0x44, 0x87, 0xe7, 0x6b, 0x4e, - 0x08, 0x52, 0x98, 0x66, 0x19, 0x97, 0x02, 0x26, 0x19, 0x05, 0xcc, 0x63, 0x7b, 0xc4, 0x36, 0x5b, - 0xc3, 0xcb, 0x1d, 0x9d, 0xac, 0x90, 0xd9, 0x5b, 0x69, 0x73, 0x8b, 0xb3, 0xf4, 0x11, 0xd2, 0xe1, - 0xa6, 0x0b, 0xc8, 0xa9, 0xb2, 0x93, 0x42, 0xeb, 0x08, 0xc9, 0x0e, 0xa6, 0xdc, 0x7b, 0xff, 0x3c, - 0xfd, 0xf6, 0x15, 0xab, 0x64, 0x78, 0xeb, 0x3a, 0x68, 0xbf, 0x69, 0xb6, 0x42, 0xbe, 0x31, 0xf7, - 0xf3, 0xc9, 0xef, 0x17, 0x17, 0xdd, 0x8f, 0x5f, 0x4f, 0x3f, 0xa3, 0x99, 0x75, 0xf8, 0xfe, 0xdd, - 0xfb, 0xa3, 0x4e, 0xe7, 0x5d, 0xeb, 0xa8, 0xd5, 0x3e, 0x3a, 0xec, 0xbc, 0x3d, 0xa8, 0xea, 0x45, - 0xa0, 0x9c, 0x41, 0xfe, 0x18, 0xec, 0x27, 0x92, 0xe1, 0x0b, 0x36, 0xd1, 0x0c, 0x4d, 0x99, 0x11, - 0xa2, 0xcd, 0x46, 0xdb, 0xbc, 0x44, 0x3d, 0xb8, 0x67, 0x81, 0x9e, 0x80, 0xc0, 0x23, 0xd8, 0xef, - 0x56, 0xb2, 0xd6, 0x08, 0xc2, 0x8b, 0x68, 0xf1, 0xbf, 0xf3, 0xdc, 0x69, 0xa0, 0x64, 0x6f, 0x9c, - 0x0d, 0x1c, 0x18, 0x8d, 0x80, 0x34, 0x30, 0x90, 0xc6, 0x38, 0x10, 0x03, 0xe1, 0xba, 0xc1, 0x21, - 0x1a, 0x22, 0x3e, 0xa4, 0xd1, 0x85, 0xa7, 0x57, 0x1c, 0x6a, 0xb2, 0x9f, 0xe9, 0xf1, 0x84, 0xe8, - 0x82, 0x0d, 0x46, 0x6c, 0xaf, 0x6c, 0x41, 0x26, 0xb9, 0x6e, 0x32, 0xd6, 0x29, 0x30, 0x11, 0x12, - 0x46, 0x49, 0x02, 0xfc, 0xb6, 0x4e, 0x2c, 0x3c, 0xd0, 0xd4, 0x36, 0x03, 0x89, 0xb9, 0x60, 0x61, - 0xfb, 0x8d, 0x19, 0xda, 0xaa, 0x36, 0xd1, 0xe6, 0x54, 0x61, 0x4c, 0x92, 0xdb, 0x8f, 0x1a, 0xa8, - 0x1b, 0x3d, 0x34, 0x66, 0xf8, 0xff, 0x7e, 0x96, 0x3b, 0x9c, 0x2e, 0x9f, 0xff, 0x62, 0xfc, 0x70, - 0x1d, 0x8f, 0x23, 0x82, 0xc6, 0x93, 0x9a, 0xe5, 0x09, 0xb2, 0xbd, 0x74, 0x39, 0x73, 0xfa, 0xda, - 0xaa, 0x84, 0x07, 0x0e, 0x15, 0x85, 0xdd, 0x23, 0xf6, 0xbf, 0xbb, 0x83, 0x7d, 0xe8, 0x9b, 0x6c, - 0x3e, 0xee, 0x57, 0xdd, 0xc9, 0xdd, 0x68, 0x49, 0xf2, 0x28, 0x72, 0x69, 0xeb, 0xb6, 0xb9, 0x8c, - 0x62, 0xf2, 0x97, 0x7e, 0xaf, 0x40, 0x6c, 0x35, 0x48, 0xda, 0x4a, 0xde, 0xec, 0x2c, 0xee, 0x1c, - 0x9a, 0x72, 0xc8, 0x92, 0x3c, 0x47, 0x29, 0xf6, 0x5d, 0xff, 0x35, 0x8d, 0xa0, 0x47, 0x45, 0x0c, - 0xbb, 0x6a, 0x18, 0xd8, 0x6d, 0xce, 0xa5, 0xcd, 0x37, 0x05, 0x4a, 0x54, 0xee, 0x63, 0x29, 0x91, - 0xfb, 0x30, 0xd7, 0xb4, 0x61, 0xbd, 0xd7, 0xc1, 0x82, 0x56, 0x15, 0xdd, 0xa1, 0x90, 0x18, 0x4f, - 0x7b, 0xc3, 0x6c, 0x6e, 0xce, 0x63, 0x93, 0xa9, 0x88, 0x69, 0x1c, 0xf7, 0x52, 0x03, 0x1f, 0x2c, - 0x86, 0xa3, 0xcb, 0x3c, 0xac, 0xc4, 0x49, 0xe5, 0x6b, 0xa0, 0xdd, 0x75, 0xc1, 0x46, 0x88, 0xce, - 0x1e, 0x46, 0x8a, 0x9e, 0x3c, 0xcd, 0xf2, 0xdf, 0x17, 0x90, 0xae, 0xed, 0x0b, 0x4b, 0x3e, 0xa7, - 0xf3, 0x0c, 0x4d, 0xb7, 0x02, 0x2b, 0x8a, 0xfe, 0x20, 0x9c, 0x28, 0xcf, 0x7b, 0x41, 0x15, 0x85, - 0x62, 0x54, 0x45, 0x2a, 0xd2, 0xe6, 0x8d, 0x5a, 0x2c, 0x1b, 0x8f, 0xf1, 0xd9, 0x9b, 0xee, 0x2c, - 0x9d, 0x2f, 0x66, 0x08, 0x6e, 0x74, 0x9d, 0x22, 0x56, 0x40, 0x53, 0x21, 0xea, 0x8d, 0x11, 0x47, - 0xa0, 0xa1, 0x3b, 0xae, 0x83, 0xcc, 0x70, 0x4a, 0x5a, 0x1e, 0x58, 0x6b, 0x77, 0xb1, 0x8a, 0x7b, - 0x04, 0xc3, 0xbf, 0x56, 0xef, 0x63, 0xa2, 0x42, 0xf7, 0xfc, 0x38, 0x7c, 0xb4, 0xeb, 0x74, 0x18, - 0xd7, 0xf8, 0x7b, 0xbc, 0x92, 0x56, 0x85, 0x6c, 0x58, 0x22, 0xc6, 0x2a, 0x78, 0x0a, 0xd3, 0x31, - 0x11, 0x89, 0x78, 0x0e, 0xdf, 0x67, 0x40, 0xa9, 0x36, 0x37, 0x9e, 0x0d, 0xe3, 0x08, 0xf5, 0x5f, - 0x68, 0x94, 0x72, 0xb8, 0xd1, 0xac, 0xe1, 0x1e, 0x06, 0xc6, 0x1e, 0x37, 0x56, 0x55, 0xed, 0xbf, - 0x6a, 0x30, 0x15, 0x4d, 0xfa, 0xaf, 0x54, 0x12, 0x4f, 0x57, 0x5a, 0xfa, 0x8e, 0x14, 0xa7, 0x24, - 0x19, 0xcb, 0x7b, 0x51, 0xb3, 0x1d, 0xde, 0xed, 0x64, 0x16, 0x3e, 0xab, 0xe9, 0xa6, 0xa5, 0x6b, - 0xdb, 0xca, 0xda, 0x22, 0x6d, 0x4e, 0x66, 0x4a, 0xca, 0x7e, 0xe6, 0x1a, 0x67, 0xae, 0x4c, 0xdf, - 0x2c, 0xee, 0xf7, 0x51, 0x07, 0x76, 0x2f, 0xe3, 0x5e, 0x9e, 0x81, 0x9f, 0xb5, 0x53, 0x98, 0xd8, - 0x9c, 0x7f, 0x0a, 0xd3, 0x59, 0x2d, 0xfc, 0x18, 0xb3, 0x9b, 0x8d, 0x7f, 0x14, 0x27, 0x0b, 0x21, - 0x60, 0x9a, 0x2b, 0x57, 0x52, 0x66, 0x05, 0x7d, 0x2a, 0x3d, 0xa1, 0xc6, 0x0f, 0xd1, 0x06, 0xfe, - 0xed, 0x52, 0xea, 0x25, 0xb5, 0x81, 0xaf, 0xfe, 0xd7, 0x08, 0x0a, 0x7b, 0xdf, 0x59, 0xdd, 0xcf, - 0x83, 0xeb, 0x75, 0xf1, 0x26, 0xa9, 0x16, 0x1b, 0x0b, 0xb7, 0xde, 0xb6, 0x52, 0xad, 0x47, 0xc5, - 0x59, 0x87, 0x1d, 0x71, 0x56, 0x08, 0xd6, 0x1c, 0x4a, 0x5a, 0x73, 0xdc, 0x52, 0xef, 0x93, 0xd0, - 0x85, 0x3d, 0x13, 0xce, 0xd0, 0xe0, 0x51, 0x6b, 0x23, 0x8b, 0xd5, 0x08, 0x1c, 0x18, 0x46, 0x51, - 0xb1, 0xe0, 0xd8, 0xa8, 0x94, 0x55, 0xc5, 0xf8, 0x07, 0x58, 0x2a, 0xed, 0x0f, 0x52, 0xcc, 0xb7, - 0x46, 0xd7, 0x51, 0xa9, 0x7f, 0xab, 0xa1, 0x6c, 0x5e, 0x42, 0x4f, 0x37, 0x74, 0xcc, 0x56, 0x27, - 0x13, 0xf1, 0x3e, 0xde, 0xed, 0xee, 0x30, 0xac, 0x61, 0xe3, 0x63, 0xed, 0xd1, 0xd7, 0x0d, 0xe9, - 0x7b, 0x69, 0x27, 0xa9, 0x9e, 0xd3, 0x81, 0xa0, 0x82, 0x81, 0xfa, 0xe4, 0x67, 0x36, 0x76, 0x70, - 0xac, 0xa1, 0x2a, 0x0f, 0x3f, 0xc9, 0xc6, 0xdf, 0x03, 0x6f, 0x9a, 0x3d, 0xf2, 0xc6, 0xcd, 0x46, - 0xbb, 0x27, 0x06, 0x5b, 0xf4, 0x41, 0x8e, 0x7f, 0x6e, 0x20, 0x2b, 0x8c, 0xfe, 0x06, 0x83, 0x55, - 0x6e, 0x1b, 0x9c, 0xab, 0x7c, 0x3c, 0x9a, 0x96, 0x1e, 0x95, 0x53, 0x40, 0xec, 0x32, 0x46, 0x01, - 0x33, 0xc9, 0x1a, 0x15, 0xa0, 0x8c, 0xab, 0x0a, 0x90, 0xaf, 0x48, 0xf6, 0xa8, 0x1d, 0xae, 0x7c, - 0x99, 0x64, 0x91, 0x02, 0xe0, 0x17, 0x06, 0xc3, 0x24, 0x9b, 0x34, 0x9c, 0x5b, 0xf5, 0xe6, 0x53, - 0xcb, 0x2a, 0xcc, 0xb3, 0x91, 0xa3, 0xea, 0xe6, 0x81, 0xa2, 0x71, 0xd7, 0x61, 0xd2, 0x04, 0xe0, - 0x15, 0x66, 0x5c, 0x6f, 0x15, 0x70, 0x6a, 0x9f, 0xef, 0x9c, 0x35, 0x1f, 0x8a, 0xbb, 0xd6, 0xb8, - 0xda, 0x2c, 0xf2, 0x4c, 0x69, 0xfb, 0x36, 0x6c, 0x72, 0x4f, 0x19, 0x29, 0x34, 0x45, 0xa1, 0xc6, - 0x22, 0xda, 0x1b, 0x5c, 0x0a, 0x66, 0x73, 0x64, 0x0f, 0xad, 0x98, 0x82, 0x48, 0x94, 0x77, 0x70, - 0x5b, 0x6a, 0x1b, 0xa0, 0xa0, 0x7c, 0x03, 0x16, 0x5d, 0x13, 0x94, 0xc9, 0xf6, 0x1c, 0x5c, 0x9c, - 0x09, 0xe1, 0xdd, 0x39, 0x78, 0x1f, 0xee, 0x06, 0x11, 0x3b, 0xbb, 0x81, 0x8d, 0x9b, 0xfb, 0xde, - 0x00, 0xaa, 0xbe, 0x0c, 0x3c, 0xfb, 0x23, 0xdd, 0xec, 0x1e, 0xc7, 0xe5, 0x3c, 0x9b, 0x98, 0xc9, - 0x94, 0x21, 0x8c, 0xb4, 0x1e, 0x69, 0x40, 0x2a, 0xc1, 0xf4, 0x22, 0xa8, 0x94, 0x6d, 0x22, 0x9a, - 0x0e, 0x8f, 0x0e, 0x57, 0x81, 0xf0, 0x3c, 0x2b, 0x27, 0x1b, 0x19, 0x3a, 0xeb, 0x88, 0xce, 0xb3, - 0x12, 0x92, 0x51, 0x66, 0x05, 0x82, 0x09, 0x54, 0xf5, 0xd5, 0xea, 0xa9, 0x8e, 0xe4, 0x2a, 0xc3, - 0x2d, 0x7f, 0x44, 0x71, 0xd7, 0x34, 0x48, 0xd2, 0x5e, 0xb4, 0x3a, 0x8a, 0xd1, 0xb6, 0x83, 0x25, - 0x7e, 0x46, 0x71, 0xb7, 0xd8, 0xc9, 0xc6, 0x0a, 0x11, 0xac, 0xb9, 0xab, 0xe5, 0x8b, 0xb4, 0x70, - 0x69, 0x2a, 0x92, 0x69, 0x82, 0x43, 0x27, 0x0a, 0x04, 0xdc, 0x9e, 0x52, 0x21, 0x6e, 0x6f, 0x42, - 0x1d, 0x47, 0x12, 0x89, 0x8a, 0x4c, 0x18, 0x94, 0x7c, 0x54, 0x9e, 0x3a, 0xc0, 0x40, 0xf0, 0x7c, - 0xc3, 0xfe, 0x38, 0x2a, 0x64, 0x9a, 0xcb, 0x50, 0xdc, 0xe7, 0x55, 0x73, 0xd8, 0x59, 0x18, 0x20, - 0xe1, 0x82, 0xfa, 0x94, 0x48, 0x0e, 0x3b, 0xde, 0x92, 0x67, 0x6a, 0xfa, 0x4d, 0x58, 0x6d, 0x79, - 0x07, 0x5a, 0x91, 0x30, 0x9f, 0x8d, 0xe3, 0x15, 0xbd, 0x21, 0x48, 0xb6, 0x82, 0x1d, 0xb9, 0x0b, - 0x9a, 0xcb, 0x86, 0xdc, 0x67, 0xcd, 0xa5, 0x1b, 0x08, 0xf2, 0x7d, 0x15, 0x74, 0xa5, 0x82, 0xae, - 0x64, 0x50, 0x53, 0x7d, 0x49, 0xb1, 0xbe, 0x44, 0xad, 0x2f, 0x29, 0xa9, 0x2f, 0x51, 0xeb, 0x4b, - 0x0a, 0xf5, 0xdd, 0xf3, 0x22, 0x25, 0xef, 0x70, 0x4f, 0xed, 0x24, 0x9f, 0x8f, 0xd1, 0x43, 0xdd, - 0x9c, 0xa4, 0x03, 0xa8, 0xd6, 0x93, 0x58, 0xea, 0xd9, 0x42, 0x21, 0x5b, 0x73, 0xdb, 0xd1, 0xbe, - 0x0f, 0xc9, 0x56, 0x87, 0xcb, 0xb8, 0x9f, 0x3e, 0xea, 0x92, 0xb7, 0xbb, 0x55, 0x6b, 0xd7, 0xcb, - 0xcd, 0x63, 0xae, 0x15, 0x8f, 0x71, 0xec, 0x50, 0xe9, 0xac, 0x6d, 0x04, 0x7a, 0x69, 0x6f, 0xbc, - 0x38, 0x81, 0xbd, 0xd9, 0xa5, 0x5c, 0xcb, 0x95, 0xdc, 0x27, 0xba, 0x90, 0x6b, 0xb9, 0x8e, 0xfb, - 0x60, 0x97, 0x71, 0x1f, 0xd9, 0xa8, 0x30, 0x5d, 0xef, 0x05, 0x41, 0x44, 0x3d, 0xff, 0xde, 0x0e, - 0xe3, 0x18, 0x3c, 0x0f, 0x4b, 0x62, 0x6f, 0x36, 0xec, 0xcd, 0x86, 0xbd, 0xd9, 0xb0, 0x37, 0x1b, - 0x2c, 0x66, 0xc3, 0x3f, 0xb3, 0x6c, 0x72, 0x7f, 0xd3, 0xe1, 0xb5, 0x5b, 0x05, 0x3b, 0x89, 0xc1, - 0x52, 0x6a, 0x3a, 0xf0, 0x71, 0xda, 0x81, 0xf9, 0x50, 0xa8, 0x6b, 0xbd, 0x35, 0xa0, 0xe8, 0xfc, - 0x0f, 0x11, 0xe4, 0x64, 0xaf, 0xfa, 0xef, 0x55, 0xff, 0xbd, 0xea, 0xff, 0xba, 0x54, 0xff, 0x8a, - 0x8a, 0xfa, 0x6e, 0x54, 0xf4, 0x43, 0x94, 0x3a, 0x86, 0xb3, 0xe8, 0x6a, 0x6c, 0x34, 0x36, 0xa5, - 0x78, 0xb6, 0xbc, 0x7f, 0xab, 0xc8, 0x12, 0x9c, 0x2b, 0x0e, 0xe7, 0xeb, 0x92, 0xf0, 0x3a, 0x9d, - 0xe7, 0x23, 0x24, 0x61, 0xbb, 0x03, 0x38, 0x46, 0x93, 0x4e, 0xf3, 0x70, 0xfd, 0xf1, 0x48, 0x50, - 0xfd, 0xa6, 0x08, 0x09, 0x2a, 0x95, 0x2a, 0x5b, 0xc1, 0x47, 0x48, 0x2e, 0xb2, 0xdd, 0x1d, 0xf3, - 0xd5, 0xd9, 0xd8, 0x2c, 0xf2, 0x62, 0x9c, 0x63, 0xbf, 0x9b, 0x04, 0xb9, 0xe5, 0x77, 0x14, 0x18, - 0x44, 0x89, 0xf4, 0x1a, 0x96, 0x5c, 0x8e, 0x1a, 0xae, 0xb9, 0x1c, 0x35, 0xac, 0x70, 0x4d, 0x62, - 0x58, 0xe5, 0x4e, 0xcc, 0x7d, 0x8f, 0xd8, 0x54, 0x3f, 0x2b, 0x51, 0x45, 0x8d, 0xc6, 0xe3, 0x21, - 0xb7, 0x02, 0x12, 0x4c, 0x31, 0x38, 0x50, 0xb2, 0xcf, 0x06, 0xc9, 0x78, 0x33, 0x88, 0x14, 0xdc, - 0x60, 0x18, 0xe4, 0xc2, 0x43, 0xdb, 0xad, 0xa4, 0x21, 0xbb, 0x95, 0x34, 0x2c, 0xbb, 0x95, 0xc4, - 0x8a, 0x6f, 0x32, 0x02, 0xc5, 0xb3, 0x1b, 0x0f, 0x78, 0x4c, 0x07, 0x4f, 0x4c, 0x32, 0x43, 0x22, - 0x69, 0xaa, 0x20, 0xc1, 0x7c, 0x1b, 0xe2, 0x8e, 0x82, 0x2b, 0x9a, 0xe0, 0x1d, 0x80, 0x0f, 0x37, - 0xa4, 0xf4, 0xb3, 0x44, 0xf2, 0xc9, 0x3c, 0x0b, 0x24, 0xa8, 0x25, 0xc1, 0xd1, 0x5c, 0xe2, 0x0b, - 0x4c, 0x6b, 0xf5, 0xbc, 0x1c, 0x1f, 0x15, 0x6c, 0xd5, 0x7e, 0xa2, 0x5d, 0x53, 0xfb, 0x80, 0xc7, - 0x07, 0xb4, 0x3f, 0xe9, 0x02, 0xe7, 0x35, 0x0e, 0x45, 0x8b, 0x7f, 0x36, 0xe7, 0x5e, 0xab, 0xd9, - 0x69, 0x77, 0xde, 0xd4, 0xc9, 0xe7, 0x00, 0x7d, 0xbe, 0x6d, 0x1f, 0x77, 0xe8, 0x67, 0x82, 0x3e, - 0x5b, 0x6f, 0x3b, 0x9d, 0x90, 0x4e, 0x6f, 0xf5, 0xd0, 0x22, 0x3f, 0x07, 0x4b, 0x18, 0x75, 0x92, - 0x80, 0x18, 0xc1, 0x62, 0x87, 0xc3, 0x1d, 0xfa, 0xe2, 0x1f, 0x0c, 0x8a, 0xd1, 0xd4, 0x23, 0x19, - 0x98, 0xbb, 0x5c, 0xe6, 0x70, 0x38, 0x34, 0x9b, 0xa2, 0xbe, 0x23, 0x07, 0x7a, 0xe1, 0xba, 0x0e, - 0x69, 0x7f, 0xd0, 0x7e, 0x73, 0xf8, 0xee, 0x08, 0x02, 0xc0, 0x72, 0xa1, 0xe7, 0x8a, 0xea, 0xe5, - 0x92, 0x20, 0xb6, 0x41, 0xd8, 0x36, 0x74, 0x01, 0xe8, 0x42, 0x54, 0x53, 0x92, 0x25, 0x3a, 0xa1, - 0x5e, 0x84, 0x02, 0x8c, 0xbe, 0x84, 0x91, 0x84, 0x84, 0xa0, 0xc3, 0xb0, 0xaa, 0xfd, 0x10, 0xc1, - 0xdd, 0x8e, 0xda, 0x7f, 0x24, 0x08, 0x2f, 0x62, 0x35, 0x16, 0x64, 0xaa, 0x5b, 0x77, 0x0c, 0xa9, - 0x1e, 0x69, 0x9e, 0x93, 0xd7, 0x31, 0x1b, 0x78, 0xb3, 0xec, 0xc6, 0x21, 0xe3, 0x15, 0xb4, 0x8f, - 0x5b, 0xf4, 0x24, 0xa8, 0x0f, 0x2d, 0x41, 0x83, 0x81, 0x3e, 0xde, 0xbf, 0xf3, 0xcd, 0x2d, 0x02, - 0x5a, 0x71, 0xc8, 0xdd, 0x2e, 0x1d, 0xcc, 0x3a, 0xed, 0x39, 0x36, 0xb6, 0x32, 0x95, 0xf2, 0x72, - 0xd2, 0x9c, 0x53, 0xf4, 0x50, 0xd7, 0xa1, 0x8c, 0x9d, 0x66, 0xbb, 0x74, 0x60, 0x29, 0xe2, 0x81, - 0x8a, 0x78, 0x60, 0x47, 0x3c, 0x28, 0x47, 0x3c, 0xd0, 0x10, 0x27, 0x2a, 0xe2, 0xc4, 0x8e, 0x38, - 0x29, 0x47, 0x9c, 0x50, 0xc4, 0xd2, 0x2d, 0x06, 0x65, 0x5d, 0x2a, 0xb9, 0x5d, 0x2b, 0xad, 0x5c, - 0xcf, 0xd6, 0xe3, 0xa6, 0x2e, 0x35, 0xec, 0x54, 0xad, 0xd1, 0x1f, 0xb7, 0x7e, 0xa1, 0x7f, 0x44, - 0x2d, 0xe3, 0x1e, 0x3a, 0x44, 0xf5, 0xed, 0x17, 0x18, 0x55, 0x5a, 0xef, 0xe0, 0x01, 0x14, 0x0e, - 0x25, 0xb8, 0x1d, 0x2c, 0x63, 0xa6, 0x10, 0x1f, 0x06, 0x3d, 0x44, 0x0d, 0xf1, 0xf1, 0xe0, 0x6a, - 0x88, 0x4c, 0xd6, 0x50, 0xbd, 0xa2, 0x2d, 0x15, 0x35, 0xeb, 0x27, 0x0a, 0x69, 0x95, 0x16, 0xc7, - 0xbd, 0x37, 0xf3, 0x29, 0xbc, 0x99, 0x98, 0x4b, 0x37, 0x52, 0xbd, 0x34, 0x9e, 0xdc, 0x4c, 0xf3, - 0xda, 0x5c, 0xdb, 0x2a, 0x70, 0x5a, 0xb4, 0x0d, 0x3f, 0xed, 0xdd, 0xa5, 0x2f, 0xe7, 0x94, 0x45, - 0x99, 0x0a, 0x4b, 0x6f, 0x90, 0xf4, 0x07, 0x29, 0xbf, 0xb3, 0x25, 0x83, 0xbc, 0x7e, 0x3f, 0xeb, - 0x43, 0xe8, 0xf0, 0x24, 0xe7, 0x36, 0xb2, 0xe8, 0xea, 0x6b, 0x75, 0xfc, 0x5b, 0x7e, 0xcc, 0x05, - 0xbc, 0x34, 0x0c, 0x77, 0x04, 0x7b, 0x90, 0xb5, 0xbf, 0xff, 0xbd, 0xc6, 0x34, 0xd5, 0x08, 0x14, - 0x55, 0x29, 0xe1, 0x16, 0x41, 0x10, 0x25, 0xfa, 0xe0, 0x27, 0xb2, 0x2e, 0x1f, 0x7c, 0x20, 0x2f, - 0x3c, 0xc8, 0xe3, 0xe9, 0xdf, 0x7a, 0x9a, 0x92, 0xb1, 0x93, 0x23, 0x27, 0xbb, 0x39, 0x70, 0x42, - 0x6b, 0x61, 0xaa, 0x83, 0xc5, 0x98, 0xa9, 0x68, 0x8d, 0x1c, 0x3e, 0x84, 0x35, 0x02, 0x57, 0x16, - 0x5f, 0x8b, 0x09, 0xc2, 0xba, 0xb5, 0x39, 0x1f, 0x70, 0xad, 0xde, 0xa6, 0xcd, 0x63, 0xcc, 0x38, - 0xac, 0x1c, 0x34, 0xc5, 0xa7, 0xbf, 0x0e, 0xdd, 0x82, 0x5e, 0x4f, 0xf3, 0xda, 0xe4, 0x69, 0x91, - 0xdd, 0xbb, 0xf9, 0xb7, 0xd1, 0x3a, 0x1f, 0x57, 0x7d, 0xdc, 0x95, 0x0e, 0xf8, 0xba, 0xf7, 0x15, - 0xf0, 0x40, 0xad, 0xd7, 0xa5, 0xac, 0xa3, 0x50, 0x4d, 0x2f, 0xda, 0xef, 0x46, 0xec, 0x77, 0x23, - 0xb6, 0xde, 0x8d, 0xa0, 0x8f, 0x03, 0x2d, 0xe9, 0x73, 0x3d, 0xf6, 0x0d, 0x89, 0xc2, 0xbe, 0x05, - 0x2d, 0xe1, 0x69, 0xf2, 0x6a, 0x1f, 0x8e, 0xc6, 0x78, 0x0c, 0xb4, 0x6a, 0xbc, 0x19, 0xa5, 0x9f, - 0x6c, 0x41, 0x67, 0x1e, 0x2a, 0x60, 0x4c, 0xa5, 0x2e, 0xef, 0x8f, 0x26, 0xb0, 0x0c, 0x67, 0xd3, - 0xb0, 0x5a, 0x64, 0x0b, 0x4a, 0xf4, 0x43, 0x8c, 0x89, 0x1c, 0xd6, 0x81, 0x04, 0xbc, 0x9a, 0x2d, - 0x46, 0x63, 0x04, 0x0b, 0xc1, 0xcc, 0x64, 0xca, 0xe8, 0xc5, 0x71, 0x6c, 0x64, 0x38, 0x52, 0x06, - 0xd2, 0xc9, 0x41, 0x1b, 0x0e, 0x94, 0x24, 0x76, 0x16, 0x58, 0x21, 0x35, 0x78, 0xd7, 0x7e, 0x8f, - 0xa3, 0x77, 0x61, 0x24, 0x75, 0x5a, 0x51, 0xc9, 0xab, 0x4a, 0xda, 0xcb, 0x71, 0x4a, 0xe8, 0xaa, - 0x2a, 0xba, 0x80, 0xbd, 0x9b, 0x75, 0xd6, 0xb9, 0xcd, 0x90, 0x70, 0x2e, 0x3c, 0xaf, 0x12, 0x2f, - 0x71, 0x3a, 0xf9, 0x46, 0xca, 0xec, 0xe9, 0x38, 0xbd, 0x06, 0xfd, 0x73, 0xea, 0xd0, 0x48, 0xcf, - 0x48, 0x08, 0xf8, 0x74, 0xd9, 0x19, 0xc5, 0x0b, 0x16, 0x52, 0x03, 0x87, 0xda, 0x2d, 0xf2, 0x15, - 0x91, 0x60, 0x1e, 0x0e, 0x10, 0xc7, 0x1f, 0xa0, 0xc2, 0x81, 0x20, 0xe7, 0x75, 0xfc, 0x67, 0x40, - 0x1f, 0xaf, 0xc2, 0x1f, 0x09, 0xf9, 0x20, 0xff, 0xba, 0x01, 0xd2, 0xf6, 0x91, 0x6a, 0x56, 0x78, - 0x8f, 0xa5, 0x7c, 0xb0, 0xb0, 0xa6, 0x2f, 0x11, 0x0d, 0x7d, 0x52, 0xc7, 0x96, 0x42, 0x83, 0x16, - 0x44, 0xa6, 0x0c, 0xff, 0xb9, 0xc2, 0xaa, 0x2f, 0x53, 0x9b, 0x13, 0x6b, 0xd9, 0x96, 0xad, 0x48, - 0xcf, 0x5a, 0x64, 0x6d, 0x6d, 0xfd, 0x2a, 0x94, 0xb6, 0x94, 0x22, 0xa9, 0xa1, 0x88, 0x9c, 0x7f, - 0x59, 0x81, 0x1a, 0x15, 0xe3, 0xa0, 0x0a, 0x11, 0x66, 0xfa, 0x87, 0x25, 0xbd, 0x65, 0x2e, 0x31, - 0xaa, 0x40, 0x9e, 0xb9, 0x64, 0xba, 0x8c, 0x07, 0x83, 0x14, 0xc7, 0xdd, 0x80, 0x19, 0x0d, 0x2c, - 0x5a, 0xfb, 0x47, 0xad, 0x83, 0x0d, 0xd0, 0x56, 0xf3, 0x08, 0x59, 0x9f, 0x3c, 0xf1, 0xa8, 0x79, - 0x8c, 0x13, 0x0f, 0x8f, 0x51, 0x2a, 0xfa, 0x43, 0xcd, 0xec, 0x74, 0x3e, 0xba, 0xa6, 0xd6, 0x75, - 0xaf, 0x7e, 0x89, 0xfe, 0x1b, 0xb9, 0x0d, 0x27, 0xae, 0xf7, 0xd1, 0x7f, 0x03, 0xd7, 0x77, 0x06, - 0xf5, 0x21, 0xfa, 0x8f, 0xa4, 0x25, 0xe8, 0xbf, 0x9e, 0xeb, 0x06, 0x35, 0xb0, 0x2b, 0x50, 0x1d, - 0xbe, 0x43, 0x90, 0x37, 0xf8, 0xf4, 0x80, 0x38, 0x13, 0x82, 0xa0, 0x7a, 0xfb, 0x7d, 0x13, 0xb1, - 0x6c, 0xa7, 0x41, 0xc0, 0xf4, 0x50, 0x5c, 0xd8, 0x96, 0xc0, 0xc2, 0x07, 0x13, 0xd1, 0x5c, 0xc2, - 0x5d, 0x00, 0x88, 0xf5, 0xe2, 0x93, 0xef, 0x15, 0xff, 0x66, 0xf1, 0xd7, 0x84, 0x39, 0xf6, 0x08, - 0x2b, 0xdf, 0x13, 0x49, 0x5b, 0x22, 0x1c, 0x4d, 0xb2, 0xb1, 0x7c, 0xc1, 0x5b, 0x2f, 0xe1, 0xc6, - 0xa8, 0xc2, 0x78, 0x2a, 0xad, 0x8d, 0x2c, 0x1d, 0x2b, 0xb4, 0xfa, 0x2e, 0xc3, 0x30, 0xee, 0x67, - 0x37, 0x7a, 0x2a, 0x08, 0x5d, 0x23, 0x78, 0xdc, 0x83, 0x88, 0x30, 0x22, 0x08, 0xe0, 0xf9, 0x59, - 0xed, 0xb0, 0xd9, 0x3e, 0x6a, 0x1f, 0xbf, 0xef, 0xbc, 0x39, 0x3e, 0x3c, 0x7e, 0xf7, 0xfe, 0xed, - 0xfb, 0xc3, 0x03, 0x43, 0x80, 0x21, 0x30, 0xef, 0xad, 0xcb, 0xac, 0xcc, 0x91, 0x0e, 0x79, 0xf0, - 0x0f, 0x99, 0x9d, 0x10, 0xdf, 0xd1, 0x95, 0x03, 0x3c, 0xe2, 0x15, 0xe3, 0x33, 0x09, 0xc8, 0xd3, - 0xcb, 0x16, 0x38, 0xc6, 0x6c, 0x3c, 0x5d, 0x38, 0x8e, 0x68, 0xf2, 0x5f, 0xad, 0xef, 0x0d, 0xe9, - 0xab, 0xfd, 0xdd, 0xf5, 0xb0, 0x25, 0x4d, 0xd5, 0x0a, 0xb7, 0xae, 0x66, 0x72, 0xcc, 0xe3, 0x6c, - 0x96, 0x46, 0x48, 0xe2, 0x4e, 0x11, 0x74, 0xe7, 0xd8, 0xa3, 0x47, 0xc5, 0x31, 0x45, 0x6e, 0x20, - 0xd5, 0xcb, 0xcf, 0x89, 0xe3, 0xd0, 0x37, 0x11, 0xe5, 0x5f, 0x62, 0xc3, 0xa3, 0x49, 0x86, 0x31, - 0x50, 0x26, 0xf6, 0x1b, 0x34, 0xd7, 0x45, 0xd3, 0xee, 0xfc, 0x0c, 0xdf, 0x77, 0x61, 0x79, 0xdc, - 0x57, 0x04, 0x5e, 0x9e, 0x0f, 0x72, 0x1b, 0xb9, 0x2d, 0x1e, 0xd1, 0xf1, 0xe2, 0xfe, 0xc0, 0xf8, - 0x76, 0x34, 0xb9, 0xc2, 0xa1, 0x8f, 0x49, 0xfa, 0xaa, 0x7e, 0x7e, 0x16, 0x4a, 0xe6, 0x4e, 0xbb, - 0xf9, 0xee, 0xed, 0x71, 0x43, 0xc4, 0x39, 0x6c, 0x37, 0xdf, 0x1e, 0xd3, 0x7c, 0x34, 0x49, 0xc9, - 0x7b, 0xa5, 0x10, 0x4f, 0x89, 0x97, 0x22, 0x81, 0x2e, 0x2f, 0x70, 0xd3, 0x79, 0x31, 0xdc, 0x14, - 0x90, 0x17, 0x68, 0x1c, 0xd0, 0x64, 0xc7, 0x5e, 0x6b, 0xdc, 0x3b, 0x64, 0x24, 0x02, 0x91, 0xca, - 0x90, 0x92, 0x0c, 0xd7, 0x63, 0xdf, 0x10, 0x33, 0x18, 0x0a, 0x30, 0xb2, 0x31, 0xc3, 0xe0, 0xf1, - 0x92, 0x2a, 0x64, 0x9b, 0xcc, 0x38, 0x93, 0x6e, 0x46, 0xe3, 0x81, 0x22, 0x29, 0xa0, 0x78, 0x91, - 0x5f, 0xd4, 0xb3, 0x21, 0x9a, 0xd5, 0x29, 0x3a, 0x77, 0x80, 0x85, 0x49, 0x44, 0x19, 0xd0, 0xf1, - 0x1d, 0x32, 0x36, 0x75, 0xda, 0x5f, 0x6e, 0x70, 0x7e, 0x86, 0x65, 0x89, 0xe0, 0x26, 0x12, 0xa2, - 0x1a, 0x0a, 0xd1, 0x9a, 0xc9, 0xcb, 0x60, 0x64, 0x26, 0xf8, 0x12, 0xf3, 0xfb, 0x18, 0x08, 0xa9, - 0x2a, 0x88, 0x93, 0x65, 0xe2, 0xcb, 0x89, 0x52, 0xe4, 0x90, 0xdc, 0x42, 0xc2, 0x8a, 0x52, 0xc5, - 0xcd, 0xd8, 0xad, 0x4b, 0x9f, 0xf7, 0x13, 0x6e, 0x7c, 0x4a, 0x9e, 0x7c, 0xf9, 0xed, 0xec, 0xe4, - 0x97, 0xb3, 0x93, 0x8b, 0xb3, 0x2f, 0x3f, 0xd7, 0x2c, 0x0f, 0x04, 0x20, 0x82, 0x39, 0x3c, 0x6e, - 0x19, 0x0e, 0xfa, 0x7c, 0xfc, 0xee, 0xed, 0x61, 0xab, 0xfd, 0xe6, 0xa0, 0xb0, 0xc3, 0x07, 0x56, - 0x13, 0x71, 0x58, 0x15, 0x77, 0xff, 0x70, 0x90, 0xf4, 0x72, 0x05, 0xb7, 0x18, 0xda, 0x17, 0xc2, - 0x45, 0x69, 0xd2, 0x09, 0xb5, 0x50, 0x7f, 0xd7, 0x50, 0x13, 0x75, 0x94, 0x02, 0x2d, 0x15, 0xc7, - 0x02, 0xea, 0x14, 0x22, 0x45, 0x0d, 0xe2, 0xc9, 0x24, 0x66, 0xa1, 0x9f, 0x0c, 0x01, 0x53, 0xc1, - 0x9a, 0x9a, 0xa6, 0x8b, 0xec, 0x32, 0x9e, 0xbf, 0xb8, 0x30, 0x3a, 0xfb, 0xa7, 0xbe, 0xb6, 0x38, - 0x66, 0x3b, 0x88, 0x67, 0x25, 0x4f, 0x65, 0xb1, 0xdc, 0xb2, 0xb8, 0xd5, 0x0c, 0x66, 0x5d, 0xe4, - 0x6a, 0x19, 0xae, 0xac, 0xcb, 0xf0, 0xeb, 0xb2, 0x96, 0x1e, 0xc3, 0x79, 0xf6, 0x0e, 0xc3, 0xd9, - 0xe5, 0x9d, 0xc2, 0x41, 0x4a, 0x48, 0x28, 0xe9, 0x90, 0xb5, 0xbd, 0x51, 0xa9, 0x2b, 0xd4, 0x7e, - 0x78, 0x7e, 0x21, 0x97, 0x5e, 0xfb, 0x83, 0x55, 0x9c, 0xe9, 0xd5, 0x81, 0x61, 0xc9, 0x06, 0x42, - 0x58, 0x96, 0x2f, 0xcf, 0x09, 0x4b, 0x08, 0x6f, 0x81, 0x66, 0x43, 0x9e, 0x97, 0x5b, 0x44, 0x5e, - 0x7c, 0x36, 0xf4, 0x08, 0xce, 0xf0, 0xc5, 0x5c, 0x30, 0xf6, 0x07, 0x2d, 0xbd, 0x09, 0xbb, 0xab, - 0x6d, 0xb0, 0xf5, 0x03, 0xeb, 0x84, 0xf2, 0x1e, 0x60, 0xcd, 0xd7, 0xf8, 0x5c, 0x09, 0x2f, 0x1a, - 0xc5, 0xec, 0xc5, 0x88, 0x46, 0xbb, 0xf3, 0x0e, 0xa9, 0xf7, 0x6c, 0x8a, 0xf1, 0xed, 0x94, 0x88, - 0x04, 0x36, 0x27, 0xef, 0x41, 0xe0, 0xa0, 0x95, 0xa0, 0xa8, 0x84, 0xd2, 0x12, 0x15, 0xf1, 0x58, - 0xe2, 0x04, 0x08, 0x5c, 0x01, 0x6e, 0x9d, 0x7e, 0xdd, 0x78, 0x6f, 0x8e, 0x68, 0x3c, 0x74, 0xe1, - 0x61, 0x95, 0x17, 0x6d, 0xf0, 0xdd, 0x2a, 0xb3, 0x97, 0x6f, 0x08, 0x4b, 0x30, 0xe0, 0xbf, 0xa5, - 0xbf, 0xe9, 0x36, 0x64, 0xc8, 0xc7, 0x97, 0xfd, 0x00, 0xbd, 0x81, 0x19, 0xbb, 0xf1, 0xf8, 0x92, - 0x64, 0x8a, 0x1c, 0x3a, 0x1a, 0x40, 0xbc, 0x47, 0x07, 0x84, 0x69, 0xb5, 0x90, 0xce, 0xb0, 0xd4, - 0x1d, 0xf6, 0x8b, 0xeb, 0xc1, 0x8a, 0xce, 0x02, 0x56, 0x2a, 0x57, 0xee, 0xb2, 0xab, 0x5c, 0x29, - 0xcb, 0xeb, 0xf5, 0x8a, 0x58, 0x3a, 0xf8, 0xc5, 0x0a, 0x50, 0x8c, 0xea, 0x8e, 0xa0, 0x8f, 0xea, - 0xe6, 0xe4, 0x39, 0x0b, 0xb9, 0x22, 0x57, 0xed, 0x14, 0x7c, 0x49, 0x94, 0x54, 0xe7, 0x89, 0xd8, - 0x99, 0x44, 0x83, 0xd0, 0xe4, 0x1a, 0x56, 0xa4, 0xa5, 0x01, 0xd4, 0xf2, 0x73, 0xe2, 0xbe, 0x44, - 0x0a, 0xe9, 0x95, 0x56, 0x07, 0xe9, 0x95, 0x4e, 0x44, 0xfe, 0xea, 0xd5, 0x78, 0x6c, 0x53, 0x10, - 0x29, 0xd3, 0x39, 0x04, 0xb2, 0x6e, 0x5c, 0xf9, 0x57, 0xf0, 0x6a, 0xbb, 0xf6, 0xa4, 0x17, 0x63, - 0x2c, 0xd5, 0xb6, 0x04, 0xfa, 0x03, 0xaa, 0x5c, 0xb1, 0x3d, 0xd0, 0xb2, 0x33, 0xa6, 0xe2, 0x85, - 0xf3, 0x8e, 0x52, 0x0c, 0xf7, 0x5f, 0xa1, 0x32, 0x63, 0xbc, 0x49, 0xfc, 0xa6, 0x16, 0xea, 0x32, - 0x39, 0x18, 0x28, 0xbb, 0x67, 0x4b, 0x6e, 0xcb, 0x5a, 0x4b, 0x99, 0x8a, 0x14, 0x2a, 0x2d, 0x84, - 0x0e, 0xf0, 0x4c, 0x7a, 0x22, 0xd8, 0xd2, 0x92, 0xba, 0x17, 0xad, 0xa7, 0x31, 0x58, 0x43, 0x50, - 0xc8, 0xd4, 0x4a, 0xe2, 0x20, 0x21, 0x4c, 0xe1, 0x63, 0x2e, 0x7e, 0xba, 0xf0, 0x78, 0x2f, 0xe8, - 0xbd, 0xaa, 0x72, 0x15, 0xdd, 0xac, 0xce, 0x1b, 0x15, 0xf7, 0xc7, 0x0d, 0xe1, 0xb7, 0x9b, 0x97, - 0x93, 0x4c, 0x57, 0xd0, 0x49, 0xdb, 0x5d, 0x8f, 0xf5, 0x4d, 0x73, 0x11, 0x0a, 0x12, 0x3a, 0x11, - 0x7e, 0xf7, 0xa7, 0x6e, 0xb6, 0xdd, 0xa0, 0x90, 0xdc, 0x47, 0xf2, 0xc5, 0x75, 0x62, 0x97, 0x4e, - 0x50, 0x7f, 0x41, 0x75, 0x0d, 0x87, 0xa3, 0xcf, 0x1b, 0x18, 0xb1, 0xeb, 0x8b, 0x0a, 0x71, 0xe4, - 0x54, 0x37, 0xc0, 0xe9, 0x16, 0xe3, 0xf5, 0x11, 0x42, 0x65, 0x71, 0xab, 0xf3, 0xd7, 0x93, 0x3f, - 0xbb, 0xbf, 0x9c, 0x7d, 0x39, 0xed, 0x7e, 0x3a, 0xbb, 0xf8, 0xed, 0xe4, 0xcb, 0xc7, 0xd3, 0xda, - 0x61, 0xe7, 0xed, 0x9b, 0xb7, 0x92, 0x5d, 0xba, 0xb7, 0x63, 0xab, 0xdb, 0xb1, 0x48, 0x72, 0x0e, - 0xe6, 0xe9, 0xc2, 0x1a, 0xc3, 0x64, 0x6f, 0x31, 0xee, 0x2d, 0xc6, 0xd7, 0x6a, 0x31, 0xee, 0x6d, - 0xb8, 0xbd, 0x0d, 0xf7, 0xcc, 0x6d, 0x38, 0x26, 0x9e, 0xab, 0x9a, 0x71, 0x41, 0x61, 0x75, 0xdc, - 0x1b, 0x76, 0x7b, 0xc3, 0x6e, 0x6f, 0xd8, 0x3d, 0x91, 0x61, 0xf7, 0x82, 0x2c, 0xaf, 0xca, 0xfb, - 0xc6, 0xdb, 0xdb, 0x64, 0xeb, 0x95, 0xd0, 0x2a, 0x27, 0x36, 0xf7, 0xa6, 0x97, 0x6e, 0x7a, 0x59, - 0x9e, 0x37, 0xa3, 0x1b, 0xe5, 0xc0, 0xae, 0x6a, 0x37, 0xdb, 0x9f, 0x39, 0x7b, 0x1c, 0x8b, 0xad, - 0x68, 0x5f, 0xb1, 0x1c, 0x65, 0xa5, 0xea, 0x5e, 0x7c, 0x3c, 0xf9, 0xe5, 0xb4, 0xd6, 0xd9, 0xc2, - 0x92, 0x7b, 0x68, 0x7b, 0xcd, 0x6e, 0x91, 0x95, 0x5b, 0x74, 0xf7, 0xb1, 0xd7, 0xc4, 0xae, 0x62, - 0xd9, 0x24, 0xda, 0x9b, 0x69, 0x0f, 0x67, 0xa6, 0x3d, 0x03, 0xab, 0xe8, 0xd9, 0x59, 0x8a, 0x3b, - 0x36, 0xd3, 0xf6, 0x97, 0x50, 0x9f, 0xd1, 0x25, 0xd4, 0x57, 0x6e, 0x0e, 0x3f, 0xad, 0xf9, 0xf9, - 0xdc, 0x8c, 0xf1, 0x5d, 0x99, 0xc3, 0xff, 0x6f, 0xae, 0x05, 0xdf, 0xdf, 0xe4, 0x67, 0x70, 0x9b, - 0x6d, 0xde, 0x1a, 0x74, 0xa8, 0xbd, 0xcd, 0xbf, 0xb7, 0xf9, 0xf7, 0x36, 0xff, 0x43, 0xd8, 0xfc, - 0x62, 0x2a, 0xc6, 0xb2, 0x82, 0x5e, 0xee, 0x0b, 0xd8, 0xe6, 0x72, 0xaa, 0x22, 0x6f, 0xf4, 0x10, - 0x2e, 0x6b, 0x6d, 0xf2, 0xdd, 0x19, 0x1a, 0xaf, 0xe5, 0x6e, 0xe8, 0xcb, 0xdf, 0x29, 0x5f, 0xef, - 0x2a, 0x79, 0x46, 0x97, 0x4c, 0x9f, 0xd0, 0x95, 0xb3, 0x0f, 0x71, 0xfc, 0xba, 0x1e, 0x3e, 0x91, - 0xbb, 0x5a, 0x6e, 0x9f, 0xda, 0xe6, 0xe6, 0xd2, 0xe3, 0xbd, 0x16, 0xa8, 0xc1, 0x82, 0x35, 0xc0, - 0x95, 0x09, 0x67, 0x62, 0xc0, 0x89, 0xa8, 0xf6, 0x68, 0x7f, 0x97, 0x61, 0x04, 0x8a, 0xc3, 0x17, - 0xe5, 0x3f, 0x24, 0xd8, 0x96, 0xa8, 0x23, 0xc9, 0x55, 0x67, 0xbe, 0x40, 0x04, 0x6a, 0x3f, 0x37, - 0x97, 0x2a, 0x7c, 0x52, 0x0e, 0x9f, 0xa8, 0xf0, 0xab, 0x2e, 0x7e, 0x31, 0xb9, 0xce, 0x7b, 0x02, - 0x29, 0x38, 0xf4, 0x46, 0x17, 0xa7, 0x0f, 0xd3, 0xe4, 0x68, 0xb5, 0xae, 0xea, 0x1d, 0xfa, 0xec, - 0x8b, 0xab, 0x13, 0xb4, 0x12, 0xc8, 0x93, 0x6d, 0x90, 0x27, 0x76, 0xe4, 0x89, 0x60, 0x0c, 0x1c, - 0xf5, 0x64, 0xf3, 0x8b, 0xe7, 0x98, 0x83, 0x50, 0xaf, 0xfa, 0xa8, 0xe5, 0xae, 0x84, 0x2b, 0xd9, - 0xe2, 0xda, 0x38, 0xc5, 0x95, 0x20, 0x5c, 0x89, 0xab, 0x78, 0x7c, 0x01, 0x97, 0xf1, 0xea, 0x38, - 0xaa, 0xd4, 0x37, 0x67, 0x24, 0xae, 0xf9, 0xca, 0x38, 0xf1, 0x01, 0x3f, 0xe0, 0xfb, 0x13, 0x2f, - 0xd8, 0x03, 0x5c, 0xe9, 0xc4, 0x0e, 0x1d, 0x2c, 0xf2, 0x6c, 0x75, 0x5c, 0x50, 0xf0, 0x50, 0xef, - 0x77, 0x57, 0x52, 0xba, 0xa9, 0x54, 0x62, 0x29, 0x95, 0x3c, 0xd2, 0xe9, 0x20, 0x9a, 0x0a, 0x95, - 0xc4, 0xa6, 0xc4, 0x64, 0x1b, 0xa5, 0x70, 0x7f, 0xdf, 0x65, 0x7f, 0x7a, 0x69, 0x7f, 0x7a, 0xa9, - 0xdc, 0x2d, 0xce, 0x86, 0xcc, 0xe0, 0x33, 0x7b, 0x08, 0x97, 0x39, 0x76, 0x14, 0x95, 0x50, 0x29, - 0xf2, 0xad, 0x7d, 0x25, 0x40, 0x4c, 0xfc, 0x25, 0xe5, 0x96, 0xf5, 0xa6, 0x0a, 0xb6, 0xbf, 0xbc, - 0xb3, 0x3f, 0xf8, 0xf5, 0x4c, 0x0e, 0x7e, 0xed, 0xce, 0xb7, 0x2d, 0x4d, 0x45, 0xf1, 0xd3, 0x50, - 0xb3, 0xc8, 0xf4, 0xd5, 0xf9, 0x69, 0x6a, 0xb2, 0x8c, 0xc9, 0x38, 0xc9, 0xf6, 0x2e, 0xe8, 0xbd, - 0x0b, 0x7a, 0xef, 0x82, 0x7e, 0x85, 0x2e, 0x68, 0xac, 0xaa, 0x47, 0x54, 0x66, 0xf0, 0x79, 0xe9, - 0xe9, 0xd6, 0x47, 0x73, 0x19, 0x48, 0x02, 0x85, 0x8f, 0x5f, 0x01, 0x6c, 0x55, 0xe7, 0x86, 0x89, - 0x4b, 0xb1, 0x27, 0x6b, 0xb1, 0x27, 0xd5, 0xb0, 0x27, 0x12, 0x76, 0x88, 0x6e, 0x56, 0xcd, 0x4d, - 0xbe, 0x3e, 0x34, 0xd7, 0xa2, 0x7f, 0x89, 0xbb, 0xb5, 0x18, 0x63, 0x09, 0x59, 0x6c, 0xcf, 0xcc, - 0x0a, 0xda, 0xdf, 0xe2, 0x2a, 0x5f, 0x87, 0x77, 0xa7, 0x07, 0x3f, 0xae, 0x12, 0xfb, 0x12, 0x2f, - 0x94, 0x19, 0x31, 0x94, 0x1c, 0x04, 0x28, 0xf6, 0x78, 0x69, 0x87, 0x6f, 0xa0, 0xae, 0xbc, 0x40, - 0xff, 0x28, 0x12, 0x42, 0x90, 0xdb, 0x8d, 0x8d, 0xd1, 0x88, 0xb0, 0x28, 0x71, 0x9b, 0xb1, 0x06, - 0x9c, 0x58, 0x81, 0x93, 0x02, 0x30, 0x76, 0xe5, 0xf1, 0x5a, 0x7c, 0x8e, 0xc2, 0xc7, 0x72, 0xce, - 0x0d, 0x89, 0x63, 0x2e, 0x52, 0xde, 0x97, 0x3d, 0x6e, 0x08, 0xe9, 0x28, 0x4b, 0x68, 0x12, 0x50, - 0xd8, 0x94, 0x43, 0xd1, 0x3e, 0xfe, 0xf1, 0xcf, 0x4a, 0x27, 0x2c, 0xf3, 0x31, 0x5a, 0x41, 0xe6, - 0xf2, 0x63, 0x14, 0x5c, 0xe6, 0xe3, 0x15, 0xc5, 0x92, 0x99, 0x5c, 0x5d, 0x5e, 0xa6, 0xf3, 0xb2, - 0x87, 0x67, 0x37, 0x0c, 0xc3, 0xd5, 0x32, 0xa4, 0xb5, 0xb7, 0x8d, 0xcd, 0xd5, 0x8a, 0x1c, 0xc7, - 0x1c, 0xbb, 0xb0, 0x01, 0x27, 0x6f, 0x03, 0x95, 0xfe, 0x9a, 0x0b, 0x51, 0x86, 0x48, 0xc9, 0x76, - 0x44, 0x42, 0xb9, 0xc1, 0x03, 0xe7, 0x72, 0x07, 0x40, 0xf8, 0x29, 0xd1, 0x55, 0x52, 0xe7, 0xca, - 0x7b, 0xc9, 0xdd, 0xdc, 0x1a, 0xd3, 0xd2, 0xba, 0xd4, 0xb6, 0xec, 0x59, 0xed, 0xca, 0xdd, 0x54, - 0x18, 0x9d, 0x39, 0xc4, 0x40, 0x42, 0xaa, 0xc4, 0x02, 0x22, 0x72, 0x97, 0x65, 0x83, 0xb0, 0x2c, - 0x8e, 0x7c, 0x8c, 0xba, 0x0d, 0x87, 0x83, 0xd3, 0xdf, 0x37, 0x61, 0x10, 0xbd, 0x6c, 0x9a, 0xcf, - 0xe3, 0x85, 0xe9, 0xfd, 0x13, 0x78, 0xa9, 0x64, 0x31, 0x1b, 0x4d, 0xbb, 0x37, 0x38, 0x0a, 0xaf, - 0x76, 0xa4, 0x5c, 0x88, 0xe5, 0x56, 0x71, 0x62, 0xb6, 0x48, 0x50, 0xb1, 0xd6, 0x9a, 0x30, 0xb1, - 0x6d, 0x02, 0xd6, 0x26, 0xd1, 0xb8, 0x09, 0xb2, 0x66, 0x4c, 0x54, 0x7f, 0x54, 0x05, 0x4d, 0x98, - 0x0f, 0x92, 0x48, 0xfc, 0x0c, 0x18, 0x58, 0x78, 0xc7, 0x0b, 0xb5, 0xf5, 0x42, 0x6d, 0x51, 0xa8, - 0x2d, 0x0a, 0xb5, 0xa1, 0x90, 0xe6, 0xef, 0x27, 0xd8, 0x7c, 0x1a, 0x05, 0x96, 0x8d, 0x3e, 0x7d, - 0x54, 0xa9, 0x89, 0x64, 0x84, 0x14, 0xcd, 0x14, 0xba, 0x84, 0xe3, 0x05, 0xb4, 0x21, 0x7c, 0xe1, - 0x68, 0xda, 0x10, 0xc9, 0x1c, 0x7d, 0xf8, 0x6a, 0x8f, 0x41, 0x84, 0x7f, 0xd7, 0xb7, 0xe4, 0xdd, - 0x2e, 0x57, 0xd6, 0xbc, 0xd5, 0xed, 0x92, 0xc7, 0x45, 0x8b, 0xaf, 0x53, 0x24, 0x1d, 0xd2, 0x88, - 0xbd, 0x40, 0xc4, 0x9e, 0x95, 0x62, 0xef, 0x49, 0xb9, 0xc1, 0x21, 0x84, 0xb1, 0x84, 0x08, 0xe1, - 0x0e, 0x85, 0x6d, 0xa0, 0x2f, 0x08, 0xdf, 0x55, 0x1c, 0x7e, 0x20, 0x18, 0x2a, 0xc4, 0xb3, 0xc7, - 0x2b, 0x0c, 0x3f, 0x99, 0x3e, 0x64, 0xe8, 0x81, 0xa1, 0xc0, 0xbe, 0x26, 0x0d, 0xd4, 0x59, 0xd1, - 0x5f, 0x9b, 0xe0, 0x32, 0x44, 0xe8, 0xb7, 0x05, 0x0f, 0x54, 0xe1, 0x57, 0x48, 0xd1, 0x24, 0x2c, - 0x96, 0x14, 0x24, 0x5e, 0x18, 0x23, 0xd2, 0xe7, 0xd5, 0xf8, 0xb8, 0xed, 0x74, 0xf8, 0x7c, 0x16, - 0xe2, 0xeb, 0x7e, 0xf2, 0x17, 0xf5, 0xd2, 0x22, 0xa7, 0x53, 0xe6, 0xfc, 0x2c, 0x2a, 0x04, 0xdb, - 0x0b, 0x8d, 0x5b, 0x26, 0xd4, 0x5a, 0x36, 0x6f, 0x99, 0x28, 0xa9, 0x87, 0x50, 0x82, 0xdb, 0x49, - 0xaa, 0xcc, 0xe5, 0x5e, 0x47, 0x60, 0x4c, 0x5d, 0x08, 0x25, 0x59, 0x36, 0x06, 0x21, 0xb3, 0x20, - 0x1b, 0x6d, 0x10, 0xe8, 0xb1, 0x8b, 0x89, 0x8d, 0x25, 0x49, 0xaf, 0x01, 0x5d, 0xa6, 0x31, 0x96, - 0xa5, 0x05, 0x38, 0xf5, 0x05, 0x3e, 0x0c, 0x5b, 0x96, 0x69, 0xc9, 0xea, 0xc5, 0x13, 0xc4, 0x83, - 0x60, 0xc8, 0x41, 0xd0, 0x35, 0x24, 0x99, 0xd9, 0x3b, 0x08, 0x16, 0xf8, 0xd9, 0x28, 0xef, 0x0d, - 0x75, 0x5a, 0xe7, 0x59, 0x1e, 0xe7, 0x69, 0x77, 0xb1, 0x9a, 0x24, 0xd9, 0xd8, 0x52, 0x90, 0x84, - 0x98, 0xd3, 0x76, 0x93, 0x14, 0x21, 0xde, 0x1b, 0xe2, 0x08, 0x8c, 0x2f, 0x60, 0xf7, 0x60, 0xcd, - 0x06, 0x1a, 0x49, 0x1d, 0xc7, 0x49, 0x8a, 0x16, 0xae, 0x71, 0x3c, 0x4d, 0x2d, 0x10, 0x03, 0xf6, - 0x7a, 0x83, 0x96, 0x2d, 0x38, 0x00, 0x44, 0xb0, 0x9e, 0x8c, 0x47, 0x80, 0x98, 0xcb, 0x93, 0x78, - 0x16, 0x5a, 0x8e, 0x5c, 0x15, 0x4d, 0xbb, 0x82, 0x61, 0xa7, 0xb0, 0xe8, 0x33, 0x79, 0x79, 0x5c, - 0xe8, 0x31, 0x91, 0x3c, 0x2b, 0xf9, 0x49, 0x13, 0xe6, 0x1d, 0x55, 0x73, 0xd9, 0x39, 0x15, 0xac, - 0x79, 0x08, 0x0f, 0x20, 0x4b, 0x84, 0x0e, 0x61, 0xa9, 0x08, 0x54, 0xe6, 0xcb, 0x45, 0x3a, 0x98, - 0x40, 0xb0, 0x41, 0xc4, 0x79, 0xe3, 0x34, 0x6a, 0x68, 0xf3, 0xfa, 0xaf, 0xce, 0x77, 0xa6, 0xa8, - 0x42, 0x9f, 0xc2, 0x02, 0xf6, 0x83, 0x65, 0xfa, 0xc2, 0x3b, 0x23, 0x3f, 0xd8, 0x67, 0x2d, 0xea, - 0x54, 0x4c, 0x05, 0x88, 0x41, 0x42, 0xd0, 0x5f, 0xad, 0xef, 0x3e, 0xfd, 0xd5, 0xfe, 0xee, 0xb3, - 0x09, 0xec, 0x06, 0x38, 0x6e, 0x71, 0x78, 0x57, 0x83, 0x3e, 0xab, 0x41, 0x8d, 0xf7, 0xab, 0x90, - 0x57, 0x56, 0x44, 0x5c, 0xd6, 0x94, 0xf5, 0x88, 0xa9, 0x54, 0xa1, 0xf8, 0xd4, 0x34, 0xd5, 0x57, - 0x76, 0x9e, 0x8d, 0xa6, 0xf9, 0xba, 0x10, 0xda, 0x34, 0x12, 0x32, 0x97, 0x46, 0x48, 0x04, 0x0d, - 0x33, 0x21, 0x8d, 0x22, 0x15, 0x5b, 0x53, 0x1d, 0x45, 0x06, 0x45, 0xa4, 0x4b, 0xa4, 0xcf, 0x91, - 0xda, 0x4f, 0x07, 0x56, 0xc4, 0x41, 0x89, 0x08, 0xac, 0x7d, 0x38, 0x28, 0xc9, 0x0d, 0xac, 0x38, - 0x15, 0xda, 0x24, 0x97, 0x16, 0x25, 0x8f, 0x98, 0x65, 0x60, 0xa7, 0x80, 0x0b, 0x53, 0xa5, 0x1d, - 0x9b, 0x5e, 0xe0, 0x59, 0x0e, 0xa1, 0x27, 0xbd, 0xa8, 0x50, 0x9a, 0x9d, 0x8b, 0x42, 0x8a, 0x00, - 0x3b, 0xff, 0x44, 0xe5, 0x44, 0xed, 0x27, 0xcc, 0xa5, 0x41, 0xe7, 0x08, 0x7b, 0x59, 0xf1, 0x48, - 0x28, 0xac, 0x8e, 0xa5, 0x33, 0x91, 0xd5, 0xa0, 0xc9, 0xa3, 0x9a, 0x42, 0xc2, 0x5f, 0x8a, 0xf8, - 0x66, 0xba, 0x22, 0x99, 0x5a, 0xe7, 0x6b, 0x07, 0x91, 0xc4, 0x5e, 0x6e, 0xe3, 0x90, 0xd0, 0xfc, - 0x5d, 0x9e, 0x58, 0x1f, 0xaf, 0xe5, 0x2a, 0x28, 0x8c, 0x20, 0x86, 0x4c, 0x22, 0x53, 0x45, 0x00, - 0x6f, 0x4c, 0xbf, 0x09, 0xf5, 0x66, 0xe0, 0xf8, 0xb1, 0x0e, 0x9c, 0x9d, 0xc2, 0x07, 0xb4, 0xd4, - 0x85, 0xc6, 0x87, 0xe3, 0x57, 0x70, 0xc6, 0x2b, 0xbc, 0x93, 0xbb, 0x02, 0xcf, 0x76, 0xc4, 0xab, - 0xd3, 0x08, 0x87, 0x29, 0x95, 0x65, 0x40, 0x5d, 0xc3, 0xaf, 0xf2, 0x27, 0x29, 0xd8, 0x43, 0xd2, - 0x09, 0x07, 0x67, 0x2d, 0x2f, 0x08, 0x0e, 0xe4, 0x1a, 0xfb, 0xa4, 0x1d, 0x17, 0x61, 0xaf, 0x32, - 0x47, 0xe3, 0x63, 0x3f, 0x3d, 0x27, 0xc7, 0xd7, 0x7f, 0xf5, 0x68, 0xa4, 0x5f, 0xd9, 0xf3, 0x0c, - 0xb2, 0xd1, 0xb4, 0xba, 0xf0, 0x31, 0x91, 0x21, 0x51, 0x47, 0x2a, 0x81, 0x6a, 0x24, 0x3b, 0x4e, - 0x5b, 0x7d, 0xa8, 0x43, 0x5a, 0x2b, 0x1c, 0xa8, 0x09, 0x37, 0x75, 0xad, 0x3d, 0x1e, 0xdf, 0xb8, - 0x0a, 0x0e, 0x21, 0x5a, 0x2f, 0xe7, 0x4b, 0x29, 0xfe, 0xf4, 0x35, 0x95, 0xca, 0xe8, 0xdf, 0x40, - 0x5a, 0xa0, 0x60, 0xf4, 0xe5, 0x25, 0x88, 0x2d, 0x27, 0xf4, 0xd3, 0x51, 0x75, 0x28, 0x1e, 0x9d, - 0x5c, 0x68, 0x0a, 0x91, 0x9c, 0x8f, 0x84, 0x28, 0xb6, 0x29, 0x20, 0x0e, 0xaf, 0xa2, 0x4f, 0xd4, - 0x3e, 0x34, 0x54, 0xfd, 0x42, 0x5d, 0xf8, 0xf8, 0xb3, 0x55, 0xe0, 0x26, 0x81, 0xd8, 0xd9, 0x0a, - 0xd2, 0xd6, 0xf7, 0xba, 0x54, 0xd4, 0xb5, 0x3a, 0x6f, 0xa9, 0xa9, 0x14, 0x3e, 0x49, 0xa8, 0xa8, - 0xcd, 0xd7, 0xf6, 0x7b, 0x3a, 0xd3, 0x64, 0xd5, 0x0b, 0x3b, 0x9a, 0x28, 0x80, 0xa7, 0xd5, 0x6b, - 0x7d, 0x2f, 0x82, 0xfe, 0x26, 0xfe, 0x20, 0x97, 0x9c, 0xbb, 0xda, 0xab, 0xfc, 0x0f, 0xaf, 0xf2, - 0xdb, 0x3c, 0xc5, 0xa3, 0xf1, 0xb8, 0xec, 0xe4, 0x92, 0xc8, 0xb7, 0x1f, 0x5f, 0x12, 0x30, 0xa6, - 0x33, 0x4c, 0x52, 0x6e, 0x99, 0xf3, 0x5f, 0x05, 0x2b, 0x7b, 0xf9, 0x29, 0x1e, 0x67, 0x65, 0x14, - 0x8b, 0x7c, 0x3b, 0xc5, 0x02, 0xc6, 0x44, 0xb1, 0x94, 0x5b, 0x46, 0xb1, 0x0a, 0xf6, 0xa2, 0x0f, - 0x3b, 0xe1, 0xa6, 0x94, 0x9c, 0x9b, 0x11, 0xf9, 0xf6, 0x47, 0x59, 0x39, 0x88, 0xf1, 0x61, 0x56, - 0x91, 0x5b, 0xfa, 0x30, 0x97, 0x02, 0xb6, 0x8e, 0x60, 0xfb, 0xb9, 0x36, 0x9e, 0x5d, 0x4e, 0xae, - 0xed, 0x84, 0x9b, 0xc8, 0x5c, 0x4b, 0xac, 0xb2, 0x37, 0xf1, 0x1c, 0x6d, 0xc1, 0xc7, 0x34, 0xd9, - 0x37, 0x75, 0x1f, 0x98, 0x4c, 0xfc, 0x6a, 0x36, 0x2b, 0x48, 0x61, 0xc5, 0xed, 0x7a, 0x48, 0x13, - 0xdb, 0x95, 0xac, 0x55, 0x49, 0xca, 0x89, 0x9f, 0xa6, 0x23, 0x56, 0x22, 0xd7, 0x57, 0x65, 0x9f, - 0xe9, 0xb0, 0x95, 0x8c, 0x6a, 0x2b, 0xf9, 0x25, 0x7e, 0x9a, 0x68, 0x11, 0xb9, 0xbe, 0x2a, 0xd5, - 0x4c, 0xb4, 0xc8, 0xa8, 0x36, 0x97, 0x4c, 0x3b, 0x3f, 0x9b, 0x25, 0x09, 0x1c, 0xf1, 0xd3, 0xf4, - 0x16, 0x2f, 0xcf, 0xf4, 0x55, 0x29, 0x64, 0x7c, 0x93, 0x57, 0xc2, 0xb4, 0x8d, 0x28, 0xe1, 0xbf, - 0x6c, 0x84, 0xd0, 0x53, 0x71, 0x92, 0x74, 0xb1, 0x92, 0x41, 0xb7, 0x2e, 0x8b, 0x32, 0x62, 0xef, - 0xd5, 0xd8, 0x7b, 0x35, 0xf6, 0x5e, 0x8d, 0xbd, 0x57, 0x63, 0xef, 0xd5, 0x78, 0x3d, 0x5e, 0x0d, - 0x76, 0x22, 0x58, 0x9c, 0x79, 0x53, 0x4e, 0xc9, 0x11, 0x3e, 0x78, 0x56, 0x8e, 0x0f, 0xf1, 0x5a, - 0xd2, 0x7c, 0x96, 0x8d, 0x63, 0x68, 0xfd, 0x3d, 0x3c, 0x21, 0x54, 0x3f, 0x23, 0x27, 0xdc, 0x50, - 0xdb, 0x9a, 0x4b, 0xb8, 0x73, 0x85, 0xaf, 0x8e, 0x11, 0x25, 0x8d, 0x6c, 0x20, 0x4a, 0x1d, 0xe4, - 0x93, 0x67, 0x40, 0x6d, 0xf5, 0x93, 0x60, 0x72, 0xf4, 0xf2, 0xd3, 0xc5, 0xa7, 0xcf, 0xdd, 0xf3, - 0x3f, 0x6b, 0xef, 0xa4, 0xfb, 0x50, 0xa7, 0x9f, 0x7e, 0x3e, 0xed, 0xfe, 0x7c, 0xf2, 0xeb, 0xaf, - 0x27, 0xa8, 0xb5, 0xed, 0xd6, 0xb1, 0xe1, 0x30, 0xcc, 0x41, 0x51, 0x6b, 0x86, 0xc5, 0xb8, 0x82, - 0x1d, 0xbc, 0x5b, 0x1b, 0x76, 0x87, 0xf6, 0xe7, 0xae, 0x4c, 0xc8, 0x9d, 0xda, 0x7f, 0x8f, 0x60, - 0xbe, 0x99, 0xbc, 0x79, 0x66, 0x93, 0x47, 0x3e, 0x6d, 0x65, 0xb1, 0xd2, 0xee, 0x61, 0xc8, 0x94, - 0x72, 0xe9, 0x66, 0x76, 0x48, 0xb9, 0x19, 0xb2, 0x91, 0x19, 0xf1, 0x18, 0xa7, 0xef, 0x24, 0xe6, - 0xd9, 0x4c, 0x9f, 0x2f, 0xe3, 0x8c, 0xcd, 0x54, 0x72, 0x10, 0xcf, 0x74, 0x78, 0x40, 0xb1, 0x2e, - 0x8a, 0x74, 0x3a, 0x4c, 0xfc, 0xb2, 0x3a, 0xd6, 0x07, 0x59, 0xe2, 0x4a, 0x96, 0xcc, 0xac, 0xf1, - 0x34, 0x53, 0xe8, 0xd8, 0x15, 0x75, 0x1a, 0x11, 0xb4, 0x81, 0x8c, 0x84, 0x34, 0xa4, 0x32, 0xfb, - 0x61, 0xe2, 0x22, 0x21, 0x0a, 0x03, 0x87, 0xe3, 0xf7, 0x14, 0xd6, 0x74, 0x43, 0xf9, 0x4c, 0xe5, - 0xd5, 0xe5, 0x65, 0xe4, 0x60, 0x55, 0xb9, 0x81, 0xef, 0x2d, 0x50, 0xb5, 0x99, 0x2b, 0xe2, 0xd0, - 0x3f, 0xec, 0x30, 0x4e, 0x24, 0xb1, 0x00, 0xa9, 0xce, 0xe1, 0xdd, 0xe7, 0xb5, 0x9b, 0xed, 0xf7, - 0x01, 0x11, 0xce, 0x75, 0x41, 0x85, 0x5b, 0x42, 0x06, 0xa9, 0x1b, 0x6a, 0x16, 0xa3, 0x19, 0x88, - 0x05, 0x95, 0x22, 0x0b, 0xef, 0x24, 0x72, 0xf1, 0x91, 0x40, 0x93, 0xbf, 0x18, 0xbc, 0xc5, 0xcd, - 0xb8, 0xd8, 0x21, 0xa4, 0xae, 0x7e, 0x84, 0x3f, 0x3c, 0x79, 0x82, 0x2a, 0x6a, 0x0e, 0xf6, 0x55, - 0x4b, 0x87, 0x08, 0x81, 0xb4, 0x86, 0x8c, 0xc0, 0x87, 0x94, 0xba, 0x92, 0x52, 0xf1, 0xc4, 0xa0, - 0xa7, 0xae, 0x64, 0xf7, 0xf2, 0x65, 0xff, 0x1f, 0x03, 0x90, 0xfe, 0x1c + 0xc5, 0x51, 0x54, 0x00, 0x59, 0xdd, 0x5c, 0x42, 0x47, 0x08, 0xc0, 0xc3, 0x11, 0xd3, 0xf5, 0x86, + 0x71, 0xaf, 0x94, 0x45, 0x32, 0xe8, 0x4a, 0xac, 0xd2, 0xae, 0x2c, 0x55, 0xd2, 0xc2, 0x6a, 0x20, + 0x6c, 0x1e, 0xa3, 0xd5, 0x77, 0x61, 0xa6, 0x8c, 0xe4, 0x29, 0xa4, 0x31, 0x35, 0x80, 0xb6, 0x98, + 0x40, 0x70, 0xea, 0x14, 0x25, 0xa1, 0x46, 0x33, 0x35, 0x0a, 0x55, 0x18, 0x56, 0xc9, 0x1a, 0x2a, + 0x93, 0xf1, 0x95, 0xa5, 0xf7, 0x20, 0x47, 0xa1, 0x10, 0xe7, 0x52, 0xf2, 0x20, 0x93, 0x13, 0x27, + 0x15, 0xc3, 0xe9, 0x1a, 0x5d, 0x05, 0xac, 0x6b, 0x48, 0xa2, 0x1c, 0x6e, 0x2e, 0x4f, 0x33, 0xad, + 0x84, 0x71, 0x75, 0xa1, 0x48, 0x9b, 0x98, 0x39, 0x76, 0xf2, 0x24, 0x98, 0x12, 0x0a, 0x17, 0xf9, + 0x3c, 0xfb, 0x77, 0x5a, 0xc6, 0x7a, 0x32, 0x84, 0x9d, 0x03, 0x65, 0x28, 0x13, 0x23, 0x2a, 0xf9, + 0x65, 0xfc, 0xa8, 0x03, 0xae, 0xa7, 0xfd, 0x66, 0xd4, 0xcf, 0x87, 0xa5, 0xb4, 0x63, 0x88, 0x32, + 0x16, 0x95, 0xe1, 0x2c, 0x8c, 0xaa, 0x80, 0xac, 0x61, 0x57, 0x1d, 0x76, 0x7d, 0x1b, 0x4a, 0x19, + 0x45, 0x85, 0xb1, 0xf2, 0x8b, 0x0a, 0x66, 0x62, 0x1b, 0x0d, 0xa2, 0x8c, 0x7b, 0x8a, 0xa0, 0xc4, + 0x5d, 0x20, 0x16, 0xc8, 0x43, 0xb4, 0x40, 0xf6, 0xe3, 0x3c, 0x96, 0xd6, 0x47, 0xf8, 0x85, 0xd6, + 0xc8, 0x52, 0xf1, 0xd6, 0x23, 0x8a, 0xae, 0x6e, 0x62, 0x52, 0x19, 0xe6, 0x73, 0x51, 0xe7, 0x32, + 0xf2, 0x74, 0x69, 0x16, 0x6d, 0x24, 0xb3, 0xc8, 0x9f, 0x48, 0xb7, 0x9d, 0x99, 0x54, 0xf2, 0x85, + 0x00, 0xe3, 0x15, 0x9a, 0x04, 0x54, 0xb4, 0x89, 0x0c, 0x82, 0x7f, 0x0c, 0x35, 0x42, 0xb2, 0xcf, + 0x84, 0x11, 0xaf, 0x4d, 0x93, 0x38, 0xd1, 0x46, 0x72, 0x85, 0xfe, 0x35, 0x54, 0x46, 0x73, 0x7c, + 0x49, 0xcc, 0x98, 0xaa, 0xe4, 0x08, 0xb6, 0x11, 0x17, 0xf2, 0x87, 0x69, 0x44, 0xe5, 0x7c, 0x5f, + 0x17, 0x24, 0xa6, 0xf1, 0x55, 0x11, 0x6e, 0x2d, 0x0a, 0xe4, 0x0f, 0x43, 0xd7, 0xc8, 0xd9, 0xbe, + 0x2e, 0x23, 0x2c, 0x5c, 0xa0, 0xa2, 0xbc, 0xc7, 0x04, 0x57, 0x3f, 0xed, 0xd4, 0x89, 0xf1, 0xd3, + 0x67, 0xbf, 0x69, 0x18, 0x75, 0xac, 0xd6, 0xe9, 0x8b, 0x7d, 0x56, 0x44, 0xa1, 0x89, 0x70, 0x85, + 0xa0, 0x2e, 0x12, 0xbb, 0x06, 0xdc, 0x5d, 0x1e, 0xfa, 0xa7, 0x21, 0xb4, 0xc6, 0xde, 0x68, 0xde, + 0x43, 0x7a, 0x13, 0xd1, 0x69, 0x22, 0x54, 0x15, 0x1e, 0x56, 0x04, 0xec, 0xb5, 0x9a, 0xc7, 0x6e, + 0x88, 0x8c, 0x70, 0x47, 0xd7, 0x9e, 0x98, 0x8a, 0xdc, 0xcb, 0xe6, 0x53, 0xa4, 0x07, 0xcd, 0x98, + 0x25, 0xa5, 0xa0, 0xa2, 0x25, 0x55, 0xad, 0x0c, 0x95, 0xd4, 0x0a, 0xd5, 0x23, 0x4a, 0xaa, 0xe7, + 0x90, 0xc9, 0x57, 0x97, 0xfb, 0x1d, 0x34, 0x48, 0x55, 0x37, 0xbb, 0xab, 0x41, 0xbf, 0x50, 0x37, + 0xd4, 0x6c, 0x9e, 0xfd, 0x2b, 0xed, 0xe5, 0x69, 0x9f, 0x91, 0xaf, 0xda, 0x72, 0x0a, 0x3d, 0xc4, + 0xa6, 0xbb, 0x5f, 0xed, 0x9e, 0xa3, 0xd7, 0xd8, 0xbc, 0x09, 0x4a, 0x34, 0x43, 0x64, 0x51, 0xd9, + 0x2d, 0x4d, 0x8d, 0x14, 0xea, 0x66, 0xa0, 0xcd, 0x2b, 0x29, 0x56, 0x6c, 0x94, 0xa5, 0xa7, 0x25, + 0x1c, 0xcd, 0xe5, 0x6a, 0xd3, 0xa6, 0x96, 0x29, 0xbc, 0x06, 0x2a, 0xb7, 0xa8, 0x41, 0x2e, 0x7d, + 0x13, 0xde, 0xdd, 0x49, 0xbc, 0x1e, 0x4f, 0xf3, 0x51, 0x3c, 0x1e, 0xc5, 0x0b, 0x2c, 0x2e, 0x11, + 0xb3, 0x06, 0x9f, 0x4e, 0xff, 0x38, 0xfb, 0x78, 0xda, 0x3d, 0x3f, 0xfb, 0xf3, 0xf4, 0x97, 0xee, + 0xb7, 0x93, 0xdf, 0xce, 0xbe, 0x06, 0xc6, 0x5a, 0x42, 0xb2, 0x60, 0x01, 0xe3, 0x1f, 0x3a, 0xb4, + 0xbe, 0xe6, 0xd2, 0x67, 0xbf, 0x56, 0xbe, 0x82, 0xda, 0xa5, 0x8e, 0x2e, 0xeb, 0x4a, 0xf6, 0xd8, + 0xea, 0xf6, 0x6e, 0x14, 0xe6, 0x47, 0xd6, 0x7c, 0x77, 0xa7, 0xbc, 0x3e, 0x85, 0xd2, 0xf9, 0x94, + 0xaa, 0xe2, 0x13, 0xe8, 0x77, 0x54, 0xb7, 0xb3, 0x4d, 0x88, 0x2a, 0x9a, 0x9a, 0x95, 0xdb, 0x2b, + 0x6b, 0x5d, 0x16, 0x3e, 0x5e, 0xaf, 0x47, 0xd9, 0x99, 0xb4, 0xaa, 0x42, 0xb4, 0x86, 0x03, 0x37, + 0xd7, 0x64, 0xd6, 0xb0, 0xd7, 0x56, 0x3a, 0xc8, 0x5a, 0xc6, 0xb9, 0xb7, 0xde, 0x80, 0xd9, 0x02, + 0x09, 0xf5, 0x90, 0x20, 0x61, 0x92, 0x7b, 0x9c, 0x4e, 0x07, 0x88, 0x32, 0xf2, 0x87, 0xc9, 0x57, + 0x37, 0xb4, 0x8a, 0x6e, 0x8a, 0xe7, 0x36, 0xd4, 0x32, 0xd1, 0x02, 0x8a, 0xf3, 0x1b, 0x93, 0x78, + 0xe9, 0x60, 0xa5, 0x59, 0x93, 0xcb, 0xca, 0x48, 0x75, 0xf3, 0x68, 0x31, 0xc9, 0xb2, 0x7c, 0xb8, + 0xc8, 0xd3, 0x99, 0xd3, 0x6a, 0xb6, 0x7c, 0x1d, 0x91, 0xaf, 0x12, 0x48, 0xf4, 0x1b, 0x82, 0x83, + 0xea, 0xa2, 0x91, 0xdc, 0x97, 0xb5, 0x7f, 0xd4, 0x10, 0x96, 0x76, 0xed, 0x27, 0xf8, 0x53, 0xfb, + 0x50, 0x93, 0xb0, 0x17, 0x30, 0x43, 0x75, 0x1a, 0x76, 0xc2, 0xb0, 0xe6, 0x05, 0x48, 0x73, 0x8d, + 0xf1, 0x16, 0x78, 0xdc, 0x49, 0xe6, 0x31, 0xbd, 0x4f, 0xe6, 0x18, 0x4f, 0xd3, 0x09, 0x25, 0x0d, + 0xfa, 0x1e, 0x8e, 0xb3, 0xc7, 0xde, 0x12, 0xb1, 0xef, 0x72, 0x08, 0x72, 0xac, 0x2b, 0xec, 0x4d, + 0x8a, 0xe6, 0x52, 0x6e, 0x16, 0x5d, 0x24, 0xcf, 0xec, 0x8a, 0x80, 0x76, 0x90, 0x7c, 0xcd, 0x09, + 0x41, 0x0a, 0xd3, 0x2c, 0xe3, 0x52, 0xa0, 0xa2, 0xdf, 0x85, 0x47, 0x6c, 0xb3, 0x35, 0xbc, 0xdc, + 0xd1, 0xc9, 0x0a, 0x99, 0xbd, 0x95, 0x36, 0xb7, 0x38, 0x4b, 0x1f, 0x21, 0x1d, 0x6e, 0xba, 0x80, + 0x9c, 0x2a, 0x3b, 0x29, 0xb4, 0x8e, 0x90, 0xec, 0x60, 0xca, 0xbd, 0xf7, 0xcf, 0xd3, 0x6f, 0x5f, + 0xb1, 0x4a, 0x86, 0xb7, 0xae, 0x83, 0xf6, 0x9b, 0x66, 0x2b, 0xe4, 0x1b, 0x73, 0x3f, 0x9f, 0xfc, + 0x7e, 0x71, 0xd1, 0xfd, 0xf8, 0xf5, 0xf4, 0x33, 0x9a, 0x59, 0x87, 0xef, 0xdf, 0xbd, 0x3f, 0xea, + 0x74, 0xde, 0xb5, 0x8e, 0x5a, 0xed, 0xa3, 0xc3, 0xce, 0xdb, 0x83, 0xaa, 0x5e, 0x04, 0xca, 0x19, + 0xe4, 0x8f, 0xc1, 0x7e, 0x22, 0x19, 0xbe, 0x60, 0x13, 0xcd, 0xd0, 0x94, 0x19, 0x21, 0xda, 0x6c, + 0xb4, 0xcd, 0x4b, 0xd4, 0x83, 0x7b, 0x16, 0xe8, 0x09, 0x08, 0x3c, 0x82, 0xfd, 0x6e, 0x25, 0x6b, + 0x8d, 0x20, 0xbc, 0x88, 0x16, 0xff, 0x3b, 0xcf, 0x9d, 0x06, 0x4a, 0xf6, 0xc6, 0xd9, 0xc0, 0x81, + 0xd1, 0x08, 0x48, 0x03, 0x03, 0x69, 0x8c, 0x03, 0x31, 0x10, 0xae, 0x1b, 0x1c, 0xa2, 0x21, 0xe2, + 0x43, 0x1a, 0x5d, 0x78, 0x7a, 0xc5, 0xa1, 0x26, 0xfb, 0x99, 0x1e, 0x4f, 0x88, 0x2e, 0xd8, 0x60, + 0xc4, 0xf6, 0xca, 0x16, 0x64, 0x92, 0xeb, 0x26, 0x63, 0x9d, 0x02, 0x13, 0x21, 0x61, 0x94, 0x24, + 0xc0, 0x6f, 0xeb, 0xc4, 0xc2, 0x03, 0x4d, 0x6d, 0x33, 0x90, 0x98, 0x0b, 0x16, 0xb6, 0xdf, 0x98, + 0xa1, 0xad, 0x6a, 0x13, 0x6d, 0x4e, 0x15, 0xc6, 0x24, 0xb9, 0xfd, 0xa8, 0x81, 0xba, 0xd1, 0x43, + 0x63, 0x86, 0xff, 0xef, 0x67, 0xb9, 0xc3, 0xe9, 0xf2, 0xf9, 0x2f, 0xc6, 0x0f, 0xd7, 0xf1, 0x38, + 0x22, 0x68, 0x3c, 0xa9, 0x59, 0x9e, 0x20, 0xdb, 0x4b, 0x97, 0x33, 0xa7, 0xaf, 0xad, 0x4a, 0x78, + 0xe0, 0x50, 0x51, 0xd8, 0x3d, 0x62, 0xff, 0xbb, 0x3b, 0xd8, 0x87, 0xbe, 0xc9, 0xe6, 0xe3, 0x7e, + 0xd5, 0x9d, 0xdc, 0x8d, 0x96, 0x24, 0x8f, 0x22, 0x97, 0xb6, 0x6e, 0x9b, 0xcb, 0x28, 0x26, 0x7f, + 0xe9, 0xf7, 0x0a, 0xc4, 0x56, 0x83, 0xa4, 0xad, 0xe4, 0xcd, 0xce, 0xe2, 0xce, 0xa1, 0x29, 0x87, + 0x2c, 0xc9, 0x73, 0x94, 0x62, 0xdf, 0xf5, 0x5f, 0xd3, 0x08, 0x7a, 0x54, 0xc4, 0xb0, 0xab, 0x86, + 0x81, 0xdd, 0xe6, 0x5c, 0xda, 0x7c, 0x53, 0xa0, 0x44, 0xe5, 0x3e, 0x96, 0x12, 0xb9, 0x0f, 0x73, + 0x4d, 0x1b, 0xd6, 0x7b, 0x1d, 0x2c, 0x68, 0x55, 0xd1, 0x1d, 0x0a, 0x89, 0xf1, 0xb4, 0x37, 0xcc, + 0xe6, 0xe6, 0x3c, 0x36, 0x99, 0x8a, 0x98, 0xc6, 0x71, 0x2f, 0x35, 0xf0, 0xc1, 0x62, 0x38, 0xba, + 0xcc, 0xc3, 0x4a, 0x9c, 0x54, 0xbe, 0x06, 0xda, 0x5d, 0x17, 0x6c, 0x84, 0xe8, 0xec, 0x61, 0xa4, + 0xe8, 0xc9, 0xd3, 0x2c, 0xff, 0x7d, 0x01, 0xe9, 0xda, 0xbe, 0xb0, 0xe4, 0x73, 0x3a, 0xcf, 0xd0, + 0x74, 0x2b, 0xb0, 0xa2, 0xe8, 0x0f, 0xc2, 0x89, 0xf2, 0xbc, 0x17, 0x54, 0x51, 0x28, 0x46, 0x55, + 0xa4, 0x22, 0x6d, 0xde, 0xa8, 0xc5, 0xb2, 0xf1, 0x18, 0x9f, 0xbd, 0xe9, 0xce, 0xd2, 0xf9, 0x62, + 0x86, 0xe0, 0x46, 0xd7, 0x29, 0x62, 0x05, 0x34, 0x15, 0xa2, 0xde, 0x18, 0x71, 0x04, 0x1a, 0xba, + 0xe3, 0x3a, 0xc8, 0x0c, 0xa7, 0xa4, 0xe5, 0x81, 0xb5, 0x76, 0x17, 0xab, 0xb8, 0x47, 0x30, 0xfc, + 0x6b, 0xf5, 0x3e, 0x26, 0x2a, 0x74, 0xcf, 0x8f, 0xc3, 0x47, 0xbb, 0x4e, 0x87, 0x71, 0x8d, 0xbf, + 0xc7, 0x2b, 0x69, 0x55, 0xc8, 0x86, 0x25, 0x62, 0xac, 0x82, 0xa7, 0x30, 0x1d, 0x13, 0x91, 0x88, + 0xe7, 0xf0, 0x7d, 0x06, 0x94, 0x1a, 0x25, 0xe3, 0xd9, 0x30, 0x8e, 0x50, 0xff, 0x85, 0x46, 0x29, + 0x87, 0x1b, 0xcd, 0x1a, 0xee, 0x61, 0x60, 0xec, 0x71, 0x63, 0x55, 0xd5, 0xfe, 0xab, 0x06, 0x53, + 0xd1, 0xa4, 0xff, 0x4a, 0x25, 0xf1, 0x74, 0xa5, 0xa5, 0xef, 0x48, 0x71, 0x4a, 0x92, 0xb1, 0xbc, + 0x17, 0x35, 0xdb, 0xe1, 0xdd, 0x4e, 0x66, 0xe1, 0xb3, 0x9a, 0x6e, 0x5a, 0xba, 0xb6, 0xad, 0xac, + 0x2d, 0xd2, 0xe6, 0x64, 0xa6, 0xa4, 0xec, 0x67, 0xae, 0x71, 0xe6, 0xca, 0xf4, 0xcd, 0xe2, 0x7e, + 0x1f, 0x75, 0x60, 0xf7, 0x32, 0xee, 0xe5, 0x19, 0xf8, 0x59, 0x3b, 0x85, 0x89, 0xcd, 0xf9, 0xa7, + 0x30, 0x9d, 0xd5, 0xc2, 0x8f, 0x31, 0xbb, 0xd9, 0xf8, 0x47, 0x71, 0xb2, 0x10, 0x02, 0xa6, 0xb9, + 0x72, 0x25, 0x65, 0x56, 0xd0, 0xa7, 0xd2, 0x13, 0x6a, 0xfc, 0x10, 0x6d, 0xe0, 0xdf, 0x2e, 0xa5, + 0x5e, 0x52, 0x1b, 0xf8, 0xea, 0x7f, 0x8d, 0xa0, 0xb0, 0xf7, 0x9d, 0xd5, 0xfd, 0x3c, 0xb8, 0x5e, + 0x17, 0x6f, 0x92, 0x6a, 0xb1, 0xb1, 0x70, 0xeb, 0x6d, 0x2b, 0xd5, 0x7a, 0x54, 0x9c, 0x75, 0xd8, + 0x11, 0x67, 0x85, 0x60, 0xcd, 0xa1, 0xa4, 0x35, 0xc7, 0x2d, 0xf5, 0x3e, 0x09, 0x5d, 0xd8, 0x33, + 0xe1, 0x0c, 0x0d, 0x1e, 0xb5, 0x36, 0xb2, 0x58, 0x8d, 0xc0, 0x81, 0x61, 0x14, 0x15, 0x0b, 0x8e, + 0x8d, 0x4a, 0x59, 0x55, 0x8c, 0x7f, 0x80, 0xa5, 0xd2, 0xfe, 0x20, 0xc5, 0x7c, 0x6b, 0x74, 0x1d, + 0x95, 0xfa, 0xb7, 0x1a, 0xca, 0xe6, 0x25, 0xf4, 0x74, 0x43, 0xc7, 0x6c, 0x75, 0x32, 0x11, 0xef, + 0xe3, 0xdd, 0xee, 0x0e, 0xc3, 0x1a, 0x36, 0x3e, 0xd6, 0x1e, 0x7d, 0xdd, 0x90, 0xbe, 0x97, 0x76, + 0x92, 0xea, 0x39, 0x1d, 0x08, 0x2a, 0x18, 0xa8, 0x4f, 0x7e, 0x66, 0x63, 0x07, 0xc7, 0x1a, 0xaa, + 0xf2, 0xf0, 0x93, 0x6c, 0xfc, 0x3d, 0xf0, 0xa6, 0xd9, 0x23, 0x6f, 0xdc, 0x6c, 0xb4, 0x7b, 0x62, + 0xb0, 0x45, 0x1f, 0xe4, 0xf8, 0xe7, 0x06, 0xb2, 0xc2, 0xe8, 0x6f, 0x30, 0x58, 0xe5, 0xb6, 0xc1, + 0xb9, 0xca, 0xc7, 0xa3, 0x69, 0xe9, 0x51, 0x39, 0x05, 0xc4, 0x2e, 0x63, 0x14, 0x30, 0x93, 0xac, + 0x51, 0x01, 0xca, 0xb8, 0xaa, 0x00, 0xf9, 0x8a, 0x64, 0x8f, 0xda, 0xe1, 0xca, 0x97, 0x49, 0x16, + 0x29, 0x00, 0x7e, 0x61, 0x30, 0x4c, 0xb2, 0x49, 0xc3, 0xb9, 0x55, 0x6f, 0x3e, 0xb5, 0xac, 0xc2, + 0x3c, 0x1b, 0x39, 0xaa, 0x6e, 0x1e, 0x28, 0x1a, 0x77, 0x1d, 0x26, 0x4d, 0x00, 0x5e, 0x61, 0xc6, + 0xf5, 0x56, 0x01, 0xa7, 0xf6, 0xf9, 0xce, 0x59, 0xf3, 0xa1, 0xb8, 0x6b, 0x8d, 0xab, 0xcd, 0x22, + 0xcf, 0x94, 0xb6, 0x6f, 0xc3, 0x26, 0xf7, 0x94, 0x91, 0x42, 0x53, 0x14, 0x6a, 0x2c, 0xa2, 0xbd, + 0xc1, 0xa5, 0x60, 0x36, 0x47, 0xf6, 0xd0, 0x8a, 0x29, 0x88, 0x44, 0x79, 0x07, 0xb7, 0xa5, 0xb6, + 0x01, 0x0a, 0xca, 0x37, 0x60, 0xd1, 0x35, 0x41, 0x99, 0x6c, 0xcf, 0xc1, 0xc5, 0x99, 0x10, 0xde, + 0x9d, 0x83, 0xf7, 0xe1, 0x6e, 0x10, 0xb1, 0xb3, 0x1b, 0xd8, 0xb8, 0xb9, 0xef, 0x0d, 0xa0, 0xea, + 0xcb, 0xc0, 0xb3, 0x3f, 0xd2, 0xcd, 0xee, 0x71, 0x5c, 0xce, 0xb3, 0x89, 0x19, 0x8f, 0x0c, 0x61, + 0xa4, 0x15, 0x56, 0x29, 0x19, 0x48, 0x25, 0x98, 0x5e, 0x04, 0x95, 0xb2, 0x4d, 0x44, 0xd3, 0xe1, + 0xd1, 0xe1, 0x2a, 0x10, 0x9e, 0x67, 0xe5, 0x64, 0x23, 0x43, 0x67, 0x1d, 0xd1, 0x79, 0x56, 0x42, + 0x32, 0xca, 0xac, 0x40, 0x30, 0x81, 0xaa, 0xbe, 0x5a, 0x3d, 0xd5, 0x91, 0x5c, 0x65, 0xb8, 0xe5, + 0x8f, 0x28, 0xee, 0x9a, 0x06, 0x49, 0xda, 0x8b, 0x56, 0x47, 0x31, 0xda, 0x76, 0xb0, 0xc4, 0xcf, + 0x28, 0xee, 0x16, 0x3b, 0xd9, 0x58, 0x21, 0x82, 0x35, 0x77, 0xb5, 0x7c, 0x91, 0x16, 0x2e, 0x4d, + 0x45, 0x32, 0x4d, 0x70, 0xe8, 0x44, 0x81, 0x80, 0xdb, 0x53, 0x2a, 0xc4, 0xed, 0x4d, 0xa8, 0xe3, + 0x48, 0x22, 0x51, 0x91, 0x09, 0x83, 0x92, 0x8f, 0xca, 0x53, 0x07, 0x18, 0x08, 0x9e, 0x6f, 0xd8, + 0x1f, 0x47, 0x85, 0x4c, 0x73, 0x19, 0x8a, 0xfb, 0xbc, 0x6a, 0x0e, 0x3b, 0x0b, 0x03, 0x24, 0x5c, + 0x50, 0x9f, 0x12, 0xc9, 0x61, 0xc7, 0x5b, 0xf2, 0x4c, 0x4d, 0xbf, 0x09, 0xab, 0x2d, 0xef, 0x40, + 0x2b, 0x12, 0xe6, 0xb3, 0x71, 0xbc, 0xa2, 0x37, 0x04, 0xc9, 0x56, 0xb0, 0x23, 0x77, 0x41, 0x73, + 0xd9, 0x90, 0xfb, 0xac, 0xb9, 0x74, 0x03, 0x41, 0xbe, 0xaf, 0x82, 0xae, 0x54, 0xd0, 0x95, 0x0c, + 0x6a, 0xaa, 0x2f, 0x29, 0xd6, 0x97, 0xa8, 0xf5, 0x25, 0x25, 0xf5, 0x25, 0x6a, 0x7d, 0x49, 0xa1, + 0xbe, 0x7b, 0x5e, 0xa4, 0xe4, 0x1d, 0xee, 0xa9, 0x9d, 0xe4, 0xf3, 0x31, 0x7a, 0xa8, 0x9b, 0x93, + 0x74, 0x00, 0xd5, 0x7a, 0x12, 0x4b, 0x3d, 0x5b, 0x28, 0x64, 0x6b, 0x6e, 0x3b, 0xda, 0xf7, 0x21, + 0x99, 0x78, 0xbc, 0x8c, 0xfb, 0xe9, 0xa3, 0x2e, 0x79, 0xbb, 0x5b, 0xb5, 0x76, 0xbd, 0xdc, 0x3c, + 0xe6, 0x5a, 0xf1, 0x18, 0xc7, 0x0e, 0x95, 0xce, 0xda, 0x46, 0xa0, 0x97, 0xf6, 0xc6, 0x8b, 0x13, + 0xd8, 0x9b, 0x5d, 0xca, 0xb5, 0x5c, 0xc9, 0x7d, 0xa2, 0x0b, 0xb9, 0x96, 0xeb, 0xb8, 0x0f, 0x76, + 0x19, 0xf7, 0x91, 0x8d, 0x0a, 0xd3, 0xf5, 0x5e, 0x10, 0x44, 0xd4, 0xf3, 0xef, 0xed, 0x30, 0x8e, + 0xc1, 0xf3, 0xb0, 0x24, 0xf6, 0x66, 0xc3, 0xde, 0x6c, 0xd8, 0x9b, 0x0d, 0x7b, 0xb3, 0xc1, 0x62, + 0x36, 0xfc, 0x33, 0xcb, 0x26, 0xf7, 0x37, 0x1d, 0x5e, 0xbb, 0x55, 0xb0, 0x93, 0x18, 0x2c, 0xa5, + 0xa6, 0x03, 0x1f, 0xa7, 0x1d, 0x98, 0x0f, 0x85, 0xba, 0xd6, 0x5b, 0x03, 0x8a, 0xce, 0xff, 0x10, + 0x41, 0x4e, 0xf6, 0xaa, 0xff, 0x5e, 0xf5, 0xdf, 0xab, 0xfe, 0xaf, 0x4b, 0xf5, 0xaf, 0xa8, 0xa8, + 0xef, 0x46, 0x45, 0x3f, 0x44, 0xa9, 0x63, 0x38, 0x8b, 0xae, 0xc6, 0x46, 0x63, 0x53, 0x8a, 0x67, + 0xcb, 0xfb, 0xb7, 0x8a, 0x2c, 0xc1, 0xb9, 0xe2, 0x70, 0xbe, 0x2e, 0x09, 0xaf, 0xd3, 0x79, 0x3e, + 0x42, 0x12, 0xb6, 0x3b, 0x80, 0x63, 0x34, 0xe9, 0x34, 0x0f, 0xd7, 0x1f, 0x8f, 0x04, 0xd5, 0x6f, + 0x8a, 0x90, 0xa0, 0x52, 0xa9, 0xb2, 0x15, 0x7c, 0x84, 0xe4, 0x22, 0xdb, 0xdd, 0x31, 0x5f, 0x9d, + 0x8d, 0xad, 0x77, 0x63, 0x51, 0x8e, 0xfd, 0x6e, 0x12, 0xe4, 0x96, 0xdf, 0x51, 0x60, 0x10, 0x25, + 0xd2, 0x6b, 0x58, 0x72, 0x39, 0x6a, 0xb8, 0xe6, 0x72, 0xd4, 0xb0, 0xc2, 0x35, 0x89, 0x61, 0x95, + 0x3b, 0x31, 0xf7, 0x3d, 0x62, 0x53, 0xfd, 0xac, 0x44, 0x15, 0x35, 0x1a, 0x8f, 0x87, 0xdc, 0x0a, + 0x48, 0x30, 0xc5, 0xe0, 0x40, 0xc9, 0x3e, 0x1b, 0x24, 0xe3, 0xcd, 0x20, 0x52, 0x70, 0x83, 0x61, + 0x90, 0x0b, 0x0f, 0x6d, 0xb7, 0x92, 0x86, 0xec, 0x56, 0xd2, 0xb0, 0xec, 0x56, 0x12, 0x2b, 0xbe, + 0xc9, 0x08, 0x14, 0xcf, 0x6e, 0x3c, 0xe0, 0x31, 0x1d, 0x3c, 0x31, 0xc9, 0x0c, 0x89, 0xa4, 0xa9, + 0x82, 0x04, 0xf3, 0x6d, 0x88, 0x3b, 0x0a, 0xae, 0x68, 0x82, 0x77, 0x00, 0x3e, 0xdc, 0x90, 0xd2, + 0xcf, 0x12, 0xc9, 0x27, 0xf3, 0x2c, 0x90, 0xa0, 0x96, 0x04, 0x47, 0x73, 0x89, 0x2f, 0x30, 0xad, + 0xd5, 0xf3, 0x72, 0x7c, 0x54, 0xb0, 0x55, 0xfb, 0x89, 0x76, 0x4d, 0xed, 0x03, 0x1e, 0x1f, 0xd0, + 0xfe, 0xa4, 0x0b, 0x9c, 0xd7, 0x38, 0x14, 0x2d, 0xfe, 0xd9, 0x9c, 0x7b, 0xad, 0x66, 0xa7, 0xdd, + 0x79, 0x53, 0x27, 0x9f, 0x03, 0xf4, 0xf9, 0xb6, 0x7d, 0xdc, 0xa1, 0x9f, 0x09, 0xfa, 0x6c, 0xbd, + 0xed, 0x74, 0x42, 0x3a, 0xbd, 0xd5, 0x43, 0x8b, 0xfc, 0x1c, 0x2c, 0x61, 0xd4, 0x49, 0x02, 0x62, + 0x04, 0x8b, 0x1d, 0x0e, 0x77, 0xe8, 0x8b, 0x7f, 0x30, 0x28, 0x46, 0x53, 0x8f, 0x64, 0x60, 0xee, + 0x72, 0x99, 0xc3, 0xe1, 0xd0, 0x6c, 0x8a, 0xfa, 0x8e, 0x1c, 0xe8, 0x85, 0xeb, 0x3a, 0xa4, 0xfd, + 0x41, 0xfb, 0xcd, 0xe1, 0xbb, 0x23, 0x08, 0x00, 0xcb, 0x85, 0x9e, 0x2b, 0xaa, 0x97, 0x4b, 0x82, + 0xd8, 0x06, 0x61, 0xdb, 0xd0, 0x05, 0xa0, 0x0b, 0x51, 0x4d, 0x49, 0x96, 0xe8, 0x84, 0x7a, 0x11, + 0x0a, 0x30, 0xfa, 0x12, 0x46, 0x12, 0x12, 0x82, 0x0e, 0xc3, 0xaa, 0xf6, 0x43, 0x04, 0x77, 0x3b, + 0x6a, 0xff, 0x91, 0x20, 0xbc, 0x88, 0xd5, 0x58, 0x90, 0xa9, 0x6e, 0xdd, 0x31, 0xa4, 0x7a, 0xa4, + 0x79, 0x4e, 0x5e, 0xc7, 0x6c, 0xe0, 0xcd, 0xb2, 0x1b, 0x87, 0x8c, 0x57, 0xd0, 0x3e, 0x6e, 0xd1, + 0x93, 0xa0, 0x3e, 0xb4, 0x04, 0x0d, 0x06, 0xfa, 0x78, 0xff, 0xce, 0x37, 0xb7, 0x08, 0x68, 0xc5, + 0x21, 0x77, 0xbb, 0x74, 0x30, 0xeb, 0xb4, 0xe7, 0xd8, 0xd8, 0xca, 0x54, 0xca, 0xcb, 0x49, 0x73, + 0x4e, 0xd1, 0x43, 0x5d, 0x87, 0x32, 0x76, 0x9a, 0xed, 0xd2, 0x81, 0xa5, 0x88, 0x07, 0x2a, 0xe2, + 0x81, 0x1d, 0xf1, 0xa0, 0x1c, 0xf1, 0x40, 0x43, 0x9c, 0xa8, 0x88, 0x13, 0x3b, 0xe2, 0xa4, 0x1c, + 0x71, 0x42, 0x11, 0x4b, 0xb7, 0x18, 0x94, 0x75, 0xa9, 0xe4, 0x76, 0xad, 0xb4, 0x72, 0x3d, 0x5b, + 0x8f, 0x9b, 0xb6, 0x5c, 0xd1, 0x53, 0xb5, 0x46, 0x7f, 0xdc, 0xfa, 0x85, 0xfe, 0x11, 0xb5, 0x8c, + 0x7b, 0xe8, 0x10, 0xd5, 0xb7, 0x5f, 0x60, 0x54, 0x69, 0xbd, 0x83, 0x07, 0x50, 0x38, 0x94, 0xe0, + 0x76, 0xb0, 0x8c, 0x99, 0x42, 0x7c, 0x18, 0xf4, 0x90, 0x02, 0xd6, 0x87, 0x55, 0x43, 0x64, 0xb2, + 0x86, 0xea, 0x15, 0x6d, 0xa9, 0xa8, 0x59, 0x3f, 0x31, 0xe0, 0xde, 0x7b, 0x33, 0x9f, 0xa1, 0x37, + 0x13, 0x73, 0xe9, 0x46, 0xaa, 0x97, 0xc6, 0x93, 0x9b, 0x69, 0x5e, 0x9b, 0x6b, 0x5b, 0x05, 0x4e, + 0x8b, 0xb6, 0xe1, 0xa7, 0xbd, 0xbb, 0xf4, 0xe5, 0x9c, 0xb2, 0x28, 0x53, 0x61, 0xe9, 0x0d, 0x92, + 0xfe, 0x20, 0xe5, 0x77, 0xb6, 0x64, 0x90, 0xd7, 0xef, 0x67, 0x7d, 0x08, 0x1d, 0x9e, 0xe4, 0xdc, + 0x46, 0x16, 0x5d, 0x7d, 0xad, 0x8e, 0x7f, 0xcb, 0x8f, 0xb9, 0x80, 0x97, 0x86, 0xe1, 0x8e, 0x60, + 0x0f, 0xb2, 0xf6, 0xf7, 0xbf, 0xd7, 0x98, 0xa6, 0x1a, 0x81, 0xa2, 0x2a, 0x25, 0xdc, 0x22, 0x08, + 0xa2, 0x44, 0x1f, 0xfc, 0x44, 0xd6, 0xe5, 0x83, 0x0f, 0xe4, 0x85, 0x07, 0x79, 0x3c, 0xfd, 0x5b, + 0x4f, 0x53, 0x32, 0x76, 0x72, 0xe4, 0x64, 0x37, 0x07, 0x4e, 0x68, 0x2d, 0x4c, 0x75, 0xb0, 0x18, + 0x33, 0x15, 0xad, 0x91, 0xc3, 0x87, 0xb0, 0x46, 0xe0, 0xca, 0xe2, 0x6b, 0x31, 0x41, 0x58, 0xb7, + 0x36, 0xe7, 0x03, 0xae, 0xd5, 0xdb, 0xb4, 0x79, 0x8c, 0x19, 0x87, 0x95, 0x83, 0xa6, 0xf8, 0xf4, + 0xd7, 0xa1, 0x5b, 0xd0, 0xeb, 0x69, 0x5e, 0x9b, 0x3c, 0x2d, 0xb2, 0x7b, 0x37, 0xff, 0x36, 0x5a, + 0xe7, 0xe3, 0xaa, 0x8f, 0xbb, 0xd2, 0x01, 0x5f, 0xf7, 0xbe, 0x02, 0x1e, 0xa8, 0xf5, 0xba, 0x94, + 0x75, 0x14, 0xaa, 0xe9, 0x45, 0xfb, 0xdd, 0x88, 0xfd, 0x6e, 0xc4, 0xd6, 0xbb, 0x11, 0xf4, 0x71, + 0xa0, 0x25, 0x7d, 0xae, 0xc7, 0xbe, 0x21, 0x51, 0xd8, 0xb7, 0xa0, 0x25, 0x3c, 0x4d, 0x5e, 0xed, + 0xc3, 0xd1, 0x18, 0x8f, 0x81, 0x56, 0x8d, 0x37, 0xa3, 0xf4, 0x93, 0x2d, 0xe8, 0xcc, 0x43, 0x05, + 0x8c, 0xa9, 0xd4, 0xe5, 0xfd, 0xd1, 0x04, 0x96, 0xe1, 0x6c, 0x1a, 0x56, 0x8b, 0x6c, 0x41, 0x89, + 0x7e, 0x88, 0x31, 0x91, 0xc3, 0x3a, 0x90, 0x80, 0x57, 0xb3, 0xc5, 0x68, 0x8c, 0x60, 0x21, 0x98, + 0x99, 0x4c, 0x19, 0xbd, 0x38, 0x8e, 0x8d, 0x0c, 0x47, 0xca, 0x40, 0x3a, 0x39, 0x68, 0xc3, 0x81, + 0x92, 0xc4, 0xce, 0x02, 0x2b, 0xa4, 0x06, 0xef, 0xda, 0xef, 0x71, 0xf4, 0x2e, 0x8c, 0xa4, 0x4e, + 0x2b, 0x2a, 0x79, 0x55, 0x49, 0x7b, 0x39, 0x4e, 0x09, 0x5d, 0x55, 0x45, 0x17, 0xb0, 0x77, 0xb3, + 0xce, 0x3a, 0xb7, 0x19, 0x12, 0xce, 0x85, 0xe7, 0x55, 0xe2, 0x25, 0x4e, 0x27, 0xdf, 0x48, 0x99, + 0x3d, 0x1d, 0xa7, 0xd7, 0xa0, 0x7f, 0x4e, 0x1d, 0x1a, 0xe9, 0x19, 0x09, 0x01, 0x9f, 0x2e, 0x3b, + 0xa3, 0x78, 0xc1, 0x42, 0x6a, 0xe0, 0x50, 0xbb, 0x45, 0xbe, 0x22, 0x12, 0xcc, 0xc3, 0x01, 0xe2, + 0xf8, 0x03, 0x54, 0x38, 0x10, 0xe4, 0xbc, 0x8e, 0xff, 0x0c, 0xe8, 0xe3, 0x55, 0xf8, 0x23, 0x21, + 0x1f, 0xe4, 0x5f, 0x37, 0x40, 0xda, 0x3e, 0x52, 0xcd, 0x0a, 0xef, 0xb1, 0x94, 0x0f, 0x16, 0xd6, + 0xf4, 0x25, 0xa2, 0xa1, 0x4f, 0xea, 0xd8, 0x52, 0x68, 0xd0, 0x82, 0xc8, 0x94, 0xe1, 0x3f, 0x57, + 0x58, 0xf5, 0x65, 0x6a, 0x73, 0x62, 0x2d, 0xdb, 0xb2, 0x15, 0xe9, 0x59, 0x8b, 0xac, 0xad, 0xad, + 0x5f, 0x85, 0xd2, 0x96, 0x52, 0x24, 0x35, 0x14, 0x91, 0xf3, 0x2f, 0x2b, 0x50, 0xa3, 0x62, 0x1c, + 0x54, 0x21, 0xc2, 0x4c, 0xff, 0xb0, 0xa4, 0xb7, 0xcc, 0x25, 0x46, 0x15, 0xc8, 0x33, 0x97, 0x4c, + 0x97, 0xf1, 0x60, 0x90, 0xe2, 0xb8, 0x1b, 0x30, 0xa3, 0x81, 0x45, 0x6b, 0xff, 0xa8, 0x75, 0xb0, + 0x01, 0xda, 0x6a, 0x1e, 0x21, 0xeb, 0x93, 0x27, 0x1e, 0x35, 0x8f, 0x71, 0xe2, 0xe1, 0x31, 0x4a, + 0x45, 0x7f, 0xa8, 0x99, 0x9d, 0xce, 0x47, 0xd7, 0xd4, 0xba, 0xee, 0xd5, 0x2f, 0xd1, 0x7f, 0x23, + 0xb7, 0xe1, 0xc4, 0xf5, 0x3e, 0xfa, 0x6f, 0xe0, 0xfa, 0xce, 0xa0, 0x3e, 0x44, 0xff, 0x91, 0xb4, + 0x04, 0xfd, 0xd7, 0x73, 0xdd, 0xa0, 0x06, 0x76, 0x05, 0xaa, 0xc3, 0x77, 0x08, 0xf2, 0x06, 0x9f, + 0x1e, 0x10, 0x67, 0x42, 0x10, 0x54, 0x6f, 0xbf, 0x6f, 0x22, 0x96, 0xed, 0x34, 0x08, 0x98, 0x1e, + 0x8a, 0x0b, 0xdb, 0x12, 0x58, 0xf8, 0x60, 0x22, 0x9a, 0x4b, 0xb8, 0x0b, 0x00, 0xb1, 0x5e, 0x7c, + 0xf2, 0xbd, 0xe2, 0xdf, 0x2c, 0xfe, 0x9a, 0x30, 0xc7, 0x1e, 0x61, 0xe5, 0x7b, 0x22, 0x69, 0x4b, + 0x84, 0xa3, 0x49, 0x36, 0x96, 0x2f, 0x78, 0xeb, 0x25, 0xdc, 0x18, 0x55, 0x18, 0x4f, 0xa5, 0xb5, + 0x91, 0xa5, 0x63, 0x85, 0x56, 0xdf, 0x65, 0x18, 0xc6, 0xfd, 0xec, 0x46, 0x4f, 0x05, 0xa1, 0x6b, + 0x04, 0x8f, 0x7b, 0x10, 0x11, 0x46, 0x04, 0x01, 0x3c, 0x3f, 0xab, 0x1d, 0x36, 0xdb, 0x47, 0xed, + 0xe3, 0xf7, 0x9d, 0x37, 0xc7, 0x87, 0xc7, 0xef, 0xde, 0xbf, 0x7d, 0x7f, 0x78, 0x60, 0x08, 0x30, + 0x04, 0xe6, 0xbd, 0x75, 0x99, 0x95, 0x39, 0xd2, 0x21, 0x0f, 0xfe, 0x21, 0xb3, 0x13, 0xe2, 0x3b, + 0xba, 0x72, 0x80, 0x47, 0xbc, 0x62, 0x7c, 0x26, 0x01, 0x79, 0x7a, 0xd9, 0x02, 0xc7, 0x98, 0x8d, + 0xa7, 0x0b, 0xc7, 0x11, 0x4d, 0xfe, 0xab, 0xf5, 0xbd, 0x21, 0x7d, 0xb5, 0xbf, 0xbb, 0x1e, 0xb6, + 0xa4, 0xa9, 0x5a, 0xe1, 0xd6, 0xd5, 0x4c, 0x8e, 0x79, 0x9c, 0xcd, 0xd2, 0x08, 0x49, 0xdc, 0x29, + 0x82, 0xee, 0x1c, 0x7b, 0xf4, 0xa8, 0x38, 0xa6, 0xc8, 0x0d, 0xa4, 0x7a, 0xf9, 0x39, 0x71, 0x1c, + 0xfa, 0x26, 0xa2, 0xfc, 0x4b, 0x6c, 0x78, 0x34, 0xc9, 0x30, 0x06, 0xca, 0xc4, 0x7e, 0x83, 0xe6, + 0xba, 0x68, 0xda, 0x9d, 0x9f, 0xe1, 0xfb, 0x2e, 0x2c, 0x8f, 0xfb, 0x8a, 0xc0, 0xcb, 0xf3, 0x41, + 0x6e, 0x23, 0xb7, 0xc5, 0x23, 0x3a, 0x5e, 0xdc, 0x1f, 0x18, 0xdf, 0x8e, 0x26, 0x57, 0x38, 0xf4, + 0x31, 0x49, 0x5f, 0xd5, 0xcf, 0xcf, 0x42, 0xc9, 0xdc, 0x69, 0x37, 0xdf, 0xbd, 0x3d, 0x6e, 0x88, + 0x38, 0x87, 0xed, 0xe6, 0xdb, 0x63, 0x9a, 0x8f, 0x26, 0x29, 0x79, 0xaf, 0x14, 0xe2, 0x29, 0xf1, + 0x52, 0x24, 0xd0, 0xe5, 0x05, 0x6e, 0x3a, 0x2f, 0x86, 0x9b, 0x02, 0xf2, 0x02, 0x8d, 0x03, 0x9a, + 0xec, 0xd8, 0x6b, 0x8d, 0x7b, 0x87, 0x8c, 0x44, 0x20, 0x52, 0x19, 0x52, 0x92, 0xe1, 0x7a, 0xec, + 0x1b, 0x62, 0x06, 0x43, 0x01, 0x46, 0x36, 0x66, 0x18, 0x3c, 0x5e, 0x52, 0x85, 0x6c, 0x93, 0x19, + 0x67, 0xd2, 0xcd, 0x68, 0x3c, 0x50, 0x24, 0x05, 0x14, 0x2f, 0xf2, 0x8b, 0x7a, 0x36, 0x44, 0xb3, + 0x3a, 0x45, 0xe7, 0x0e, 0xb0, 0x30, 0x89, 0x28, 0x03, 0x3a, 0xbe, 0x43, 0xc6, 0xa6, 0x4e, 0xfb, + 0xcb, 0x0d, 0xce, 0xcf, 0xb0, 0x2c, 0x11, 0xdc, 0x44, 0x42, 0x54, 0x43, 0x21, 0x5a, 0x33, 0x79, + 0x19, 0x8c, 0xcc, 0x04, 0x5f, 0x62, 0x7e, 0x1f, 0x03, 0x21, 0x55, 0x05, 0x71, 0xb2, 0x4c, 0x7c, + 0x39, 0x51, 0x8a, 0x1c, 0x92, 0x5b, 0x48, 0x58, 0x51, 0xaa, 0xb8, 0x19, 0xbb, 0x75, 0xe9, 0xf3, + 0x7e, 0xc2, 0x8d, 0x4f, 0xc9, 0x93, 0x2f, 0xbf, 0x9d, 0x9d, 0xfc, 0x72, 0x76, 0x72, 0x71, 0xf6, + 0xe5, 0xe7, 0x9a, 0xe5, 0x81, 0x00, 0x44, 0x30, 0x87, 0xc7, 0x2d, 0xc3, 0x41, 0x9f, 0x8f, 0xdf, + 0xbd, 0x3d, 0x6c, 0xb5, 0xdf, 0x1c, 0x14, 0x76, 0xf8, 0xc0, 0x6a, 0x22, 0x0e, 0xab, 0xe2, 0xee, + 0x1f, 0x0e, 0x92, 0x5e, 0xae, 0xe0, 0x16, 0x43, 0xfb, 0x42, 0xb8, 0x28, 0x4d, 0x3a, 0xa1, 0x16, + 0xea, 0xef, 0x1a, 0x6a, 0xa2, 0x8e, 0x52, 0xa0, 0xa5, 0xe2, 0x58, 0x40, 0x9d, 0x42, 0xa4, 0xa8, + 0x41, 0x3c, 0x99, 0xc4, 0x2c, 0xf4, 0x93, 0x21, 0x60, 0x2a, 0x58, 0x53, 0xd3, 0x74, 0x91, 0x5d, + 0xc6, 0xf3, 0x17, 0x17, 0x46, 0x67, 0xff, 0xd4, 0xd7, 0x16, 0xc7, 0x6c, 0x07, 0xf1, 0xac, 0xe4, + 0xa9, 0x2c, 0x96, 0x5b, 0x16, 0xb7, 0x9a, 0xc1, 0xac, 0x8b, 0x5c, 0x2d, 0xc3, 0x95, 0x75, 0x19, + 0x7e, 0x5d, 0xd6, 0xd2, 0x24, 0x9c, 0x67, 0xef, 0x30, 0x9c, 0x5d, 0xde, 0x29, 0x1c, 0xa4, 0x84, + 0x84, 0x92, 0x0e, 0x59, 0xdb, 0x1b, 0x95, 0xba, 0x42, 0xed, 0x87, 0xe7, 0x17, 0x72, 0xe9, 0xb5, + 0x3f, 0x58, 0xc5, 0x99, 0x5e, 0x1d, 0x18, 0x96, 0x6c, 0x20, 0x84, 0x65, 0xf9, 0xf2, 0x9c, 0xb0, + 0x84, 0xf0, 0x16, 0x68, 0x36, 0xe4, 0x79, 0xb9, 0x45, 0xe4, 0xc5, 0x67, 0x43, 0x8f, 0xe0, 0x0c, + 0x5f, 0xcc, 0x05, 0x63, 0x7f, 0xd0, 0xd2, 0x9b, 0xb0, 0xbb, 0xda, 0x06, 0x5b, 0x3f, 0xb0, 0x4e, + 0x28, 0xef, 0x01, 0xd6, 0x7c, 0x8d, 0xcf, 0x95, 0xf0, 0xa2, 0x51, 0xcc, 0x5e, 0x8c, 0x68, 0xb4, + 0x3b, 0xef, 0x90, 0x7a, 0x4f, 0x15, 0xa3, 0x2e, 0xdf, 0x4e, 0x89, 0x48, 0x60, 0x73, 0xf2, 0x1e, + 0x04, 0x0e, 0x5a, 0x09, 0x8a, 0x4a, 0x28, 0x2d, 0x51, 0x11, 0x8f, 0x25, 0x4e, 0x80, 0xc0, 0x15, + 0xe0, 0xd6, 0xe9, 0xd7, 0x8d, 0xf7, 0xe6, 0x88, 0xc6, 0x43, 0x17, 0x1e, 0x56, 0x79, 0xd1, 0x06, + 0xdf, 0xad, 0x32, 0x7b, 0xf9, 0x86, 0xb0, 0x04, 0x03, 0xfe, 0x5b, 0xfa, 0x9b, 0x6e, 0x43, 0x86, + 0x7c, 0x7c, 0xd9, 0x0f, 0xd0, 0x1b, 0x98, 0xb1, 0x1b, 0x8f, 0x2f, 0x49, 0xa6, 0xc8, 0xa1, 0xa3, + 0x01, 0xc4, 0x7b, 0x74, 0x40, 0x98, 0x56, 0x0b, 0xe9, 0x0c, 0x4b, 0xdd, 0x61, 0xbf, 0xb8, 0x1e, + 0xac, 0xe8, 0x2c, 0x60, 0xa5, 0x72, 0xe5, 0x2e, 0xbb, 0xca, 0x95, 0xb2, 0xbc, 0x5e, 0xaf, 0x88, + 0xa5, 0x83, 0x5f, 0xac, 0x00, 0xc5, 0xa8, 0xee, 0x08, 0xfa, 0xa8, 0x6e, 0x4e, 0x9e, 0xb3, 0x90, + 0x2b, 0x72, 0xd5, 0x4e, 0xc1, 0x97, 0x44, 0x49, 0x75, 0x9e, 0x88, 0x9d, 0x49, 0x34, 0x08, 0x4d, + 0xae, 0x61, 0x45, 0x5a, 0x1a, 0x40, 0x2d, 0x3f, 0x27, 0xee, 0x4b, 0xa4, 0x90, 0x5e, 0x69, 0x75, + 0x90, 0x5e, 0xe9, 0x44, 0xe4, 0xaf, 0x5e, 0x8d, 0xc7, 0x36, 0x05, 0x91, 0x32, 0x9d, 0x43, 0x20, + 0xeb, 0xc6, 0x95, 0x7f, 0x05, 0xaf, 0xb6, 0x6b, 0x4f, 0x7a, 0x31, 0xc6, 0x52, 0x6d, 0x4b, 0xa0, + 0x3f, 0xa0, 0xca, 0x15, 0xdb, 0x03, 0x2d, 0x3b, 0x63, 0x2a, 0x5e, 0x38, 0xef, 0x28, 0xc5, 0x70, + 0xff, 0x15, 0x2a, 0x33, 0xc6, 0x9b, 0xc4, 0x6f, 0x6a, 0xa1, 0x2e, 0x93, 0x83, 0x81, 0xb2, 0x7b, + 0xb6, 0xe4, 0xb6, 0xac, 0xb5, 0x94, 0xa9, 0x48, 0xa1, 0xd2, 0x42, 0xe8, 0x00, 0xcf, 0xa4, 0x27, + 0x82, 0x2d, 0x2d, 0xa9, 0x7b, 0xd1, 0x7a, 0x1a, 0x83, 0x35, 0x04, 0x85, 0x4c, 0xad, 0x24, 0x0e, + 0x12, 0xc2, 0x14, 0x3e, 0xe6, 0xe2, 0xa7, 0x0b, 0x8f, 0xf7, 0x82, 0xde, 0xab, 0x2a, 0x57, 0xd1, + 0xcd, 0xea, 0xbc, 0x51, 0x71, 0x7f, 0xdc, 0x10, 0x7e, 0xbb, 0x79, 0x39, 0xc9, 0x74, 0x05, 0x9d, + 0xb4, 0xdd, 0xf5, 0x58, 0xdf, 0x34, 0x17, 0xa1, 0x20, 0xa1, 0x13, 0xe1, 0x77, 0x7f, 0xea, 0x66, + 0xdb, 0x0d, 0x0a, 0xc9, 0x7d, 0x24, 0x5f, 0x5c, 0x27, 0x76, 0xe9, 0x04, 0xf5, 0x17, 0x54, 0xd7, + 0x70, 0x38, 0xfa, 0xbc, 0x81, 0x11, 0xbb, 0xbe, 0xa8, 0x10, 0x47, 0x4e, 0x75, 0x03, 0x9c, 0x6e, + 0x31, 0x5e, 0x1f, 0x21, 0x54, 0x16, 0xb7, 0x3a, 0x7f, 0x3d, 0xf9, 0xb3, 0xfb, 0xcb, 0xd9, 0x97, + 0xd3, 0xee, 0xa7, 0xb3, 0x8b, 0xdf, 0x4e, 0xbe, 0x7c, 0x3c, 0xad, 0x1d, 0x76, 0xde, 0xbe, 0x79, + 0x2b, 0xd9, 0xa5, 0x7b, 0x3b, 0xb6, 0xba, 0x1d, 0x8b, 0x24, 0xe7, 0x60, 0x9e, 0x2e, 0xac, 0x31, + 0x4c, 0xf6, 0x16, 0xe3, 0xde, 0x62, 0x7c, 0xad, 0x16, 0xe3, 0xde, 0x86, 0xdb, 0xdb, 0x70, 0xcf, + 0xdc, 0x86, 0x63, 0xe2, 0xb9, 0xaa, 0x19, 0x17, 0x14, 0x56, 0xc7, 0xbd, 0x61, 0xb7, 0x37, 0xec, + 0xf6, 0x86, 0xdd, 0x13, 0x19, 0x76, 0x2f, 0xc8, 0xf2, 0xaa, 0xbc, 0x6f, 0xbc, 0xbd, 0x4d, 0xb6, + 0x5e, 0x09, 0xad, 0x72, 0x62, 0x73, 0x6f, 0x7a, 0xe9, 0xa6, 0x97, 0xe5, 0x79, 0x33, 0xba, 0x51, + 0x0e, 0xec, 0xaa, 0x76, 0xb3, 0xfd, 0x99, 0xb3, 0xc7, 0xb1, 0xd8, 0x8a, 0xf6, 0x15, 0xcb, 0x51, + 0x56, 0xaa, 0xee, 0xc5, 0xc7, 0x93, 0x5f, 0x4e, 0x6b, 0x9d, 0x2d, 0x2c, 0xb9, 0x87, 0xb6, 0xd7, + 0xec, 0x16, 0x59, 0xb9, 0x45, 0x77, 0x1f, 0x7b, 0x4d, 0xec, 0x2a, 0x96, 0x4d, 0xa2, 0xbd, 0x99, + 0xf6, 0x70, 0x66, 0xda, 0x33, 0xb0, 0x8a, 0x9e, 0x9d, 0xa5, 0xb8, 0x63, 0x33, 0x6d, 0x7f, 0x09, + 0xf5, 0x19, 0x5d, 0x42, 0x7d, 0xe5, 0xe6, 0xf0, 0xd3, 0x9a, 0x9f, 0xcf, 0xcd, 0x18, 0xdf, 0x95, + 0x39, 0xfc, 0xff, 0xe6, 0x5a, 0xf0, 0xfd, 0x4d, 0x7e, 0x06, 0xb7, 0xd9, 0xe6, 0xad, 0x41, 0x87, + 0xda, 0xdb, 0xfc, 0x7b, 0x9b, 0x7f, 0x6f, 0xf3, 0x3f, 0x84, 0xcd, 0x2f, 0xa6, 0x62, 0x2c, 0x2b, + 0xe8, 0xe5, 0xbe, 0x80, 0x6d, 0x2e, 0xa7, 0x2a, 0xf2, 0x46, 0x0f, 0xe1, 0xb2, 0xd6, 0x26, 0xdf, + 0x9d, 0xa1, 0xf1, 0x5a, 0xee, 0x86, 0xbe, 0xfc, 0x9d, 0xf2, 0xf5, 0xae, 0x92, 0x67, 0x74, 0xc9, + 0xf4, 0x09, 0x5d, 0x39, 0xfb, 0x10, 0xc7, 0xaf, 0xeb, 0xe1, 0x13, 0xb9, 0xab, 0xe5, 0xf6, 0xa9, + 0x6d, 0x6e, 0x2e, 0x3d, 0xde, 0x6b, 0x81, 0x1a, 0x2c, 0x58, 0x03, 0x5c, 0x99, 0x70, 0x26, 0x06, + 0x9c, 0x88, 0x6a, 0x8f, 0xf6, 0x77, 0x19, 0x46, 0xa0, 0x38, 0x7c, 0x51, 0xfe, 0x43, 0x82, 0x6d, + 0x89, 0x3a, 0x92, 0x5c, 0x75, 0xe6, 0x0b, 0x44, 0xa0, 0xf6, 0x73, 0x73, 0xa9, 0xc2, 0x27, 0xe5, + 0xf0, 0x89, 0x0a, 0xbf, 0xea, 0xe2, 0x17, 0x93, 0xeb, 0xbc, 0x27, 0x90, 0x82, 0x43, 0x6f, 0x74, + 0x71, 0xfa, 0x30, 0x4d, 0x8e, 0x56, 0xeb, 0xaa, 0xde, 0xa1, 0xcf, 0xbe, 0xb8, 0x3a, 0x41, 0x2b, + 0x81, 0x3c, 0xd9, 0x06, 0x79, 0x62, 0x47, 0x9e, 0x08, 0xc6, 0xc0, 0x51, 0x4f, 0x36, 0xbf, 0x78, + 0x8e, 0x39, 0x08, 0xf5, 0xaa, 0x8f, 0x5a, 0xee, 0x4a, 0xb8, 0x92, 0x2d, 0xae, 0x8d, 0x53, 0x5c, + 0x09, 0xc2, 0x95, 0xb8, 0x8a, 0xc7, 0x17, 0x70, 0x19, 0xaf, 0x8e, 0xa3, 0x4a, 0x7d, 0x73, 0x46, + 0xe2, 0x9a, 0xaf, 0x8c, 0x13, 0x1f, 0xf0, 0x03, 0xbe, 0x3f, 0xf1, 0x82, 0x3d, 0xc0, 0x95, 0x4e, + 0xec, 0xd0, 0xc1, 0x22, 0xcf, 0x56, 0xc7, 0x05, 0x05, 0x0f, 0xf5, 0x7e, 0x77, 0x25, 0xa5, 0x9b, + 0x4a, 0x25, 0x96, 0x52, 0xc9, 0x23, 0x9d, 0x0e, 0xa2, 0xa9, 0x50, 0x49, 0x6c, 0x4a, 0x4c, 0xb6, + 0x51, 0x0a, 0xf7, 0xf7, 0x5d, 0xf6, 0xa7, 0x97, 0xf6, 0xa7, 0x97, 0xca, 0xdd, 0xe2, 0x6c, 0xc8, + 0x0c, 0x3e, 0xb3, 0x87, 0x70, 0x99, 0x63, 0x47, 0x51, 0x09, 0x95, 0x22, 0xdf, 0xda, 0x57, 0x02, + 0xc4, 0xc4, 0x5f, 0x52, 0x6e, 0x59, 0x6f, 0xaa, 0x60, 0xfb, 0xcb, 0x3b, 0xfb, 0x83, 0x5f, 0xcf, + 0xe4, 0xe0, 0xd7, 0xee, 0x7c, 0xdb, 0xd2, 0x54, 0x14, 0x3f, 0x0d, 0x35, 0x8b, 0x4c, 0x5f, 0x9d, + 0x9f, 0xa6, 0x26, 0xcb, 0x98, 0x8c, 0x93, 0x6c, 0xef, 0x82, 0xde, 0xbb, 0xa0, 0xf7, 0x2e, 0xe8, + 0x57, 0xe8, 0x82, 0xc6, 0xaa, 0x7a, 0x44, 0x65, 0x06, 0x9f, 0x97, 0x9e, 0x6e, 0x7d, 0x34, 0x97, + 0x81, 0x24, 0x50, 0xf8, 0xf8, 0x15, 0xc0, 0x56, 0x75, 0x6e, 0x98, 0xb8, 0x14, 0x7b, 0xb2, 0x16, + 0x7b, 0x52, 0x0d, 0x7b, 0x22, 0x61, 0x87, 0xe8, 0x66, 0xd5, 0xdc, 0xe4, 0xeb, 0x43, 0x73, 0x2d, + 0xfa, 0x97, 0xb8, 0x5b, 0x8b, 0x31, 0x96, 0x90, 0xc5, 0xf6, 0xcc, 0xac, 0xa0, 0xfd, 0x2d, 0xae, + 0xf2, 0x75, 0x78, 0x77, 0x7a, 0xf0, 0xe3, 0x2a, 0xb1, 0x2f, 0xf1, 0x42, 0x99, 0x11, 0x43, 0xc9, + 0x41, 0x80, 0x62, 0x8f, 0x97, 0x76, 0xf8, 0x06, 0xea, 0xca, 0x0b, 0xf4, 0x8f, 0x22, 0x21, 0x04, + 0xb9, 0xdd, 0xd8, 0x18, 0x8d, 0x08, 0x8b, 0x12, 0xb7, 0x19, 0x6b, 0xc0, 0x89, 0x15, 0x38, 0x29, + 0x00, 0x63, 0x57, 0x1e, 0xaf, 0xc5, 0xe7, 0x28, 0x7c, 0x2c, 0xe7, 0xdc, 0x90, 0x38, 0xe6, 0x22, + 0xe5, 0x7d, 0xd9, 0xe3, 0x86, 0x90, 0x8e, 0xb2, 0x84, 0x26, 0x01, 0x85, 0x4d, 0x39, 0x14, 0xed, + 0xe3, 0x1f, 0xff, 0xac, 0x74, 0xc2, 0x32, 0x1f, 0xa3, 0x15, 0x64, 0x2e, 0x3f, 0x46, 0xc1, 0x65, + 0x3e, 0x5e, 0x51, 0x2c, 0x99, 0xc9, 0xd5, 0xe5, 0x65, 0x3a, 0x2f, 0x7b, 0x78, 0x76, 0xc3, 0x30, + 0x5c, 0x2d, 0x43, 0x5a, 0x7b, 0xdb, 0xd8, 0x5c, 0xad, 0xc8, 0x71, 0xcc, 0xb1, 0x0b, 0x1b, 0x70, + 0xf2, 0x36, 0x50, 0xe9, 0xaf, 0xb9, 0x10, 0x65, 0x88, 0x94, 0x6c, 0x47, 0x24, 0x94, 0x1b, 0x3c, + 0x70, 0x2e, 0x77, 0x00, 0x84, 0x9f, 0x12, 0x5d, 0x25, 0x75, 0xae, 0xbc, 0x97, 0xdc, 0xcd, 0xad, + 0x31, 0x2d, 0xad, 0x4b, 0x6d, 0xcb, 0x9e, 0xd5, 0xae, 0xdc, 0x4d, 0x85, 0xd1, 0x99, 0x43, 0x0c, + 0x24, 0xa4, 0x4a, 0x2c, 0x20, 0x22, 0x77, 0x59, 0x36, 0x08, 0xcb, 0xe2, 0xc8, 0xc7, 0xa8, 0xdb, + 0x70, 0x38, 0x38, 0xfd, 0x7d, 0x13, 0xe1, 0x54, 0x9c, 0xe6, 0xf3, 0x78, 0x61, 0x7a, 0xff, 0x04, + 0x5e, 0x2a, 0x59, 0xcc, 0x46, 0xd3, 0xee, 0x0d, 0x8e, 0xc2, 0xab, 0x1d, 0x29, 0x17, 0x62, 0xb9, + 0x55, 0x9c, 0x98, 0x2d, 0x12, 0x54, 0xac, 0xb5, 0x26, 0x4c, 0x6c, 0x9b, 0x80, 0xb5, 0x49, 0x34, + 0x6e, 0x82, 0xac, 0x19, 0x13, 0xd5, 0x1f, 0x55, 0x41, 0x13, 0xe6, 0x83, 0x24, 0x12, 0x3f, 0x03, + 0x06, 0x16, 0xde, 0xf1, 0x42, 0x6d, 0xbd, 0x50, 0x5b, 0x14, 0x6a, 0x8b, 0x42, 0x6d, 0x28, 0xa4, + 0xf9, 0xfb, 0x09, 0x36, 0x9f, 0x46, 0x81, 0x65, 0xa3, 0x4f, 0x1f, 0x55, 0x6a, 0x22, 0x19, 0x21, + 0x45, 0x33, 0x85, 0x2e, 0xe1, 0x78, 0x01, 0x6d, 0x08, 0x5f, 0x38, 0x9a, 0x36, 0x44, 0x32, 0x47, + 0x1f, 0xbe, 0xda, 0x63, 0x10, 0xe1, 0xdf, 0xf5, 0x2d, 0x79, 0xb7, 0xcb, 0x95, 0x35, 0x6f, 0x75, + 0xbb, 0xe4, 0x71, 0xd1, 0xe2, 0xeb, 0x14, 0x49, 0x87, 0x34, 0x62, 0x2f, 0x10, 0xb1, 0x67, 0xa5, + 0xd8, 0x7b, 0x52, 0x6e, 0x70, 0x08, 0x61, 0x2c, 0x21, 0x42, 0xb8, 0x43, 0x61, 0x1b, 0xe8, 0x0b, + 0xc2, 0x77, 0x15, 0x87, 0x1f, 0x08, 0x86, 0x0a, 0xf1, 0xec, 0xf1, 0x0a, 0xc3, 0x4f, 0xa6, 0x0f, + 0x19, 0x7a, 0x60, 0x28, 0xb0, 0xaf, 0x49, 0x03, 0x75, 0x56, 0xf4, 0xd7, 0x26, 0xb8, 0x0c, 0x11, + 0xfa, 0x6d, 0xc1, 0x03, 0x55, 0xf8, 0x15, 0x52, 0x34, 0x09, 0x8b, 0x25, 0x05, 0x89, 0x17, 0xc6, + 0x88, 0xf4, 0x79, 0x35, 0x3e, 0x6e, 0x3b, 0x1d, 0x3e, 0x9f, 0x85, 0xf8, 0xba, 0x9f, 0xfc, 0x45, + 0xbd, 0xb4, 0xc8, 0xe9, 0x94, 0x39, 0x3f, 0x8b, 0x0a, 0xc1, 0xf6, 0x42, 0xe3, 0x96, 0x09, 0xb5, + 0x96, 0xcd, 0x5b, 0x26, 0x4a, 0xea, 0x21, 0x94, 0xe0, 0x76, 0x92, 0x2a, 0x73, 0x99, 0x1b, 0x01, + 0x33, 0xa6, 0x2e, 0x84, 0x92, 0x2c, 0x1b, 0x83, 0x90, 0x59, 0x90, 0x8d, 0x36, 0x08, 0xf4, 0xd8, + 0xc5, 0xc4, 0xc6, 0x92, 0xa4, 0xd7, 0x80, 0x2e, 0xd3, 0x18, 0xcb, 0xd2, 0x02, 0x9c, 0xfa, 0x02, + 0x1f, 0x86, 0x2d, 0xcb, 0xb4, 0x64, 0xf5, 0xe2, 0x09, 0xe2, 0x41, 0x30, 0xe4, 0x20, 0xe8, 0x1a, + 0x92, 0xcc, 0xec, 0x1d, 0x04, 0x0b, 0xfc, 0x6c, 0x94, 0xf7, 0x86, 0x3a, 0xad, 0xf3, 0x2c, 0x8f, + 0xf3, 0xb4, 0xbb, 0x58, 0x4d, 0x92, 0x6c, 0x6c, 0x29, 0x48, 0x42, 0xcc, 0x69, 0xbb, 0x49, 0x8a, + 0x10, 0xef, 0x0d, 0x71, 0x04, 0xc6, 0x17, 0xb0, 0x7b, 0xb0, 0x66, 0x03, 0x8d, 0xa4, 0x8e, 0xe3, + 0x24, 0x45, 0x0b, 0xd7, 0x38, 0x9e, 0xa6, 0x16, 0x88, 0x01, 0x7b, 0xbd, 0x41, 0xcb, 0x16, 0x1c, + 0x00, 0x22, 0x58, 0x4f, 0xc6, 0x23, 0x40, 0xcc, 0xe5, 0x49, 0x3c, 0x0b, 0x2d, 0x47, 0xae, 0x8a, + 0xa6, 0x5d, 0xc1, 0xb0, 0x53, 0x58, 0xf4, 0x99, 0xbc, 0x3c, 0x2e, 0xf4, 0x98, 0x48, 0x9e, 0x95, + 0xfc, 0xa4, 0x09, 0x73, 0x93, 0xaa, 0xb9, 0xec, 0x9c, 0x0a, 0xd6, 0x3c, 0x84, 0x07, 0x90, 0x25, + 0x42, 0x87, 0xb0, 0x54, 0x04, 0x2a, 0xf3, 0xe5, 0x22, 0x1d, 0x4c, 0x20, 0xd8, 0x20, 0xe2, 0xbc, + 0x71, 0x1a, 0x35, 0xb4, 0x79, 0xfd, 0x57, 0xe7, 0x3b, 0x53, 0x54, 0xa1, 0x4f, 0x61, 0x01, 0xfb, + 0xc1, 0x32, 0x7d, 0xe1, 0x9d, 0x91, 0x1f, 0xec, 0xb3, 0x16, 0x75, 0x2a, 0xa6, 0x02, 0xc4, 0x20, + 0x21, 0xe8, 0xaf, 0xd6, 0x77, 0x9f, 0xfe, 0x6a, 0x7f, 0xf7, 0xd9, 0x04, 0x76, 0x03, 0x1c, 0xb7, + 0x38, 0xbc, 0xab, 0x41, 0x9f, 0xd5, 0xa0, 0xc6, 0xfb, 0x55, 0xc8, 0x2b, 0x2b, 0x22, 0x2e, 0x6b, + 0xca, 0x7a, 0xc4, 0x54, 0xaa, 0x50, 0x7c, 0x6a, 0x9a, 0xea, 0x2b, 0x3b, 0xcf, 0x46, 0xd3, 0x7c, + 0x5d, 0x08, 0x6d, 0x1a, 0x09, 0x99, 0x4b, 0x23, 0x24, 0x82, 0x86, 0x99, 0x90, 0x46, 0x91, 0x8a, + 0xad, 0xa9, 0x8e, 0x22, 0x83, 0x22, 0xd2, 0x25, 0xd2, 0xe7, 0x48, 0xed, 0xa7, 0x03, 0x2b, 0xe2, + 0xa0, 0x44, 0x04, 0xd6, 0x3e, 0x1c, 0x94, 0xe4, 0x06, 0x56, 0x9c, 0x0a, 0x6d, 0x92, 0x4b, 0x8b, + 0x92, 0x47, 0xcc, 0x32, 0xb0, 0x53, 0xc0, 0x85, 0xa9, 0xd2, 0x8e, 0x4d, 0x2f, 0xf0, 0x2c, 0x87, + 0xd0, 0x93, 0x5e, 0x54, 0x28, 0xcd, 0xce, 0x45, 0x21, 0x45, 0x80, 0x9d, 0x7f, 0xa2, 0x72, 0xa2, + 0xf6, 0x13, 0xe6, 0xd2, 0xa0, 0x73, 0x84, 0xbd, 0xac, 0x78, 0x24, 0x14, 0x56, 0xc7, 0xd2, 0x99, + 0xc8, 0x6a, 0xd0, 0xe4, 0x51, 0x4d, 0x21, 0xe1, 0x2f, 0x45, 0x7c, 0x33, 0x5d, 0x91, 0x4c, 0xad, + 0xf3, 0xb5, 0x83, 0x48, 0x62, 0x2f, 0xb7, 0x71, 0x48, 0x68, 0xfe, 0x2e, 0x4f, 0xac, 0x8f, 0xd7, + 0x72, 0x15, 0x14, 0x46, 0x10, 0x43, 0x26, 0x91, 0xa9, 0x22, 0x80, 0x37, 0xa6, 0xdf, 0x84, 0x7a, + 0x33, 0x70, 0xfc, 0x58, 0x07, 0xce, 0x4e, 0xe1, 0x03, 0x5a, 0xea, 0x42, 0xe3, 0xc3, 0xf1, 0x2b, + 0x38, 0xe3, 0x15, 0xde, 0xc9, 0x5d, 0x81, 0x67, 0x3b, 0xe2, 0xd5, 0x69, 0x84, 0xc3, 0x94, 0xca, + 0x32, 0xa0, 0xae, 0xe1, 0x57, 0xf9, 0x93, 0x14, 0xec, 0x21, 0xe9, 0x84, 0x83, 0xb3, 0x96, 0x17, + 0x04, 0x07, 0x72, 0x8d, 0x7d, 0xd2, 0x8e, 0x8b, 0xb0, 0x57, 0x99, 0xa3, 0xf1, 0xb1, 0x9f, 0x9e, + 0x93, 0xe3, 0xeb, 0xbf, 0x7a, 0x34, 0xd2, 0xaf, 0xec, 0x79, 0x06, 0xd9, 0x68, 0x5a, 0x5d, 0xf8, + 0x98, 0xc8, 0x90, 0xa8, 0x23, 0x95, 0x40, 0x35, 0x92, 0x1d, 0xa7, 0xad, 0x3e, 0xd4, 0x21, 0xad, + 0x15, 0x0e, 0xd4, 0x84, 0x9b, 0xba, 0xd6, 0x1e, 0x8f, 0x6f, 0x5c, 0x05, 0x87, 0x10, 0xad, 0x97, + 0xf3, 0xa5, 0x14, 0x7f, 0xfa, 0x9a, 0x4a, 0x65, 0xf4, 0x6f, 0x20, 0x2d, 0x50, 0x30, 0xfa, 0xf2, + 0x12, 0xc4, 0x96, 0x13, 0xfa, 0xe9, 0xa8, 0x3a, 0x14, 0x8f, 0x4e, 0x2e, 0x34, 0x85, 0x48, 0xce, + 0x47, 0x42, 0x14, 0xdb, 0x14, 0x10, 0x87, 0x57, 0xd1, 0x27, 0x6a, 0x1f, 0x1a, 0xaa, 0x7e, 0xa1, + 0x2e, 0x7c, 0xfc, 0xd9, 0x2a, 0x70, 0x93, 0x40, 0xec, 0x6c, 0x05, 0x69, 0xeb, 0x7b, 0x5d, 0x2a, + 0xea, 0x5a, 0x9d, 0xb7, 0xd4, 0x54, 0x0a, 0x9f, 0x24, 0x54, 0xd4, 0xe6, 0x6b, 0xfb, 0x3d, 0x9d, + 0x69, 0x12, 0x10, 0x71, 0x34, 0x51, 0x00, 0x4f, 0xab, 0xd7, 0xfa, 0x5e, 0x04, 0xfd, 0x4d, 0xfc, + 0x41, 0x2e, 0x39, 0x77, 0xb5, 0x57, 0xf9, 0x1f, 0x5e, 0xe5, 0xb7, 0x79, 0x8a, 0x47, 0xe3, 0x71, + 0xd9, 0xc9, 0x25, 0x91, 0x6f, 0x3f, 0xbe, 0x24, 0x60, 0x4c, 0x67, 0x98, 0xa4, 0xdc, 0x32, 0xe7, + 0xbf, 0x0a, 0x56, 0xf6, 0xf2, 0x53, 0x3c, 0xce, 0xca, 0x28, 0x16, 0xf9, 0x76, 0x8a, 0x05, 0x8c, + 0x89, 0x62, 0x29, 0xb7, 0x8c, 0x62, 0x15, 0xec, 0x45, 0x1f, 0x76, 0xc2, 0x4d, 0x29, 0x39, 0x37, + 0x23, 0xf2, 0xed, 0x8f, 0xb2, 0x72, 0x10, 0xe3, 0xc3, 0xac, 0x22, 0xb7, 0xf4, 0x61, 0x2e, 0x05, + 0x6c, 0x1d, 0xc1, 0xf6, 0x73, 0x6d, 0x3c, 0xbb, 0x9c, 0x5c, 0xdb, 0x09, 0x37, 0x91, 0xb9, 0x96, + 0x58, 0x65, 0x6f, 0xe2, 0x39, 0xda, 0x82, 0x8f, 0x69, 0xb2, 0x6f, 0xea, 0x3e, 0x30, 0x99, 0xf8, + 0xd5, 0x6c, 0x56, 0x90, 0xc2, 0x8a, 0xdb, 0xf5, 0x90, 0x26, 0xb6, 0x2b, 0x59, 0xab, 0x92, 0x94, + 0x13, 0x3f, 0x4d, 0x47, 0xac, 0x44, 0xae, 0xaf, 0xca, 0x3e, 0xd3, 0x61, 0x2b, 0x19, 0xd5, 0x56, + 0xf2, 0x4b, 0xfc, 0x34, 0xd1, 0x22, 0x72, 0x7d, 0x55, 0xaa, 0x99, 0x68, 0x91, 0x51, 0x6d, 0x2e, + 0x99, 0x76, 0x7e, 0x36, 0x4b, 0x12, 0x38, 0xe2, 0xa7, 0xe9, 0x2d, 0x5e, 0x9e, 0xe9, 0xab, 0x52, + 0xc8, 0xf8, 0x26, 0xaf, 0x84, 0x69, 0x1b, 0x51, 0xc2, 0x7f, 0xd9, 0x08, 0xa1, 0xa7, 0xe2, 0x24, + 0xe9, 0x62, 0x25, 0x83, 0x6e, 0x5d, 0x16, 0x65, 0xc4, 0xde, 0xab, 0xb1, 0xf7, 0x6a, 0xec, 0xbd, + 0x1a, 0x7b, 0xaf, 0xc6, 0xde, 0xab, 0xf1, 0x7a, 0xbc, 0x1a, 0xec, 0x44, 0xb0, 0x38, 0xf3, 0xa6, + 0x9c, 0x92, 0x23, 0x7c, 0xf0, 0xac, 0x1c, 0x1f, 0xe2, 0xb5, 0xa4, 0xf9, 0x2c, 0x1b, 0xc7, 0xd0, + 0xfa, 0x7b, 0x78, 0x42, 0xa8, 0x7e, 0x46, 0x4e, 0xb8, 0xa1, 0xb6, 0x35, 0x97, 0x70, 0xe7, 0x0a, + 0x5f, 0x1d, 0x23, 0x4a, 0x1a, 0xd9, 0x40, 0x94, 0x3a, 0xc8, 0x27, 0xcf, 0x80, 0xda, 0xea, 0x27, + 0xc1, 0xe4, 0xe8, 0xe5, 0xa7, 0x8b, 0x4f, 0x9f, 0xbb, 0xe7, 0x7f, 0xd6, 0xde, 0x49, 0xf7, 0xa1, + 0x4e, 0x3f, 0xfd, 0x7c, 0xda, 0xfd, 0xf9, 0xe4, 0xd7, 0x5f, 0x4f, 0x50, 0x6b, 0xdb, 0xad, 0x63, + 0xc3, 0x61, 0x98, 0x83, 0xa2, 0xd6, 0x0c, 0x8b, 0x71, 0x05, 0x3b, 0x78, 0xb7, 0x36, 0xec, 0x0e, + 0xed, 0xcf, 0x5d, 0x99, 0x90, 0x3b, 0xb5, 0xff, 0x1e, 0xc1, 0x7c, 0x33, 0x79, 0xf3, 0xcc, 0x26, + 0x8f, 0x7c, 0xda, 0xca, 0x62, 0xa5, 0xdd, 0xc3, 0x90, 0x29, 0xe5, 0xd2, 0xcd, 0xec, 0x90, 0x72, + 0x33, 0x64, 0x23, 0x33, 0xe2, 0x31, 0x4e, 0xdf, 0x49, 0xcc, 0xb3, 0x99, 0x3e, 0x5f, 0xc6, 0x19, + 0x9b, 0xa9, 0xe4, 0x20, 0x9e, 0xe9, 0xf0, 0x80, 0x62, 0x5d, 0x14, 0xe9, 0x74, 0x98, 0xf8, 0x65, + 0x75, 0xac, 0x0f, 0xb2, 0xc4, 0x95, 0x2c, 0x99, 0x59, 0xe3, 0x69, 0xa6, 0xd0, 0xb1, 0x2b, 0xea, + 0x34, 0x22, 0x68, 0x03, 0x19, 0x09, 0x69, 0x48, 0x65, 0xf6, 0xc3, 0xc4, 0x45, 0x42, 0x14, 0x06, + 0x0e, 0xc7, 0xef, 0x29, 0xac, 0xe9, 0x86, 0xf2, 0x99, 0xca, 0xab, 0xcb, 0xcb, 0xc8, 0xc1, 0xaa, + 0x72, 0x03, 0xdf, 0x5b, 0xa0, 0x6a, 0x33, 0x57, 0xc4, 0xa1, 0x7f, 0xd8, 0x61, 0x9c, 0x48, 0x62, + 0x01, 0x52, 0x9d, 0xc3, 0xbb, 0xcf, 0x6b, 0x37, 0xdb, 0xef, 0x03, 0x22, 0x9c, 0xeb, 0x82, 0x0a, + 0xb7, 0x84, 0x0c, 0x52, 0x37, 0xd4, 0x2c, 0x46, 0x33, 0x10, 0x0b, 0x2a, 0x45, 0x16, 0xde, 0x49, + 0xe4, 0xe2, 0x23, 0x81, 0x26, 0x7f, 0x31, 0x78, 0x8b, 0x9b, 0x71, 0xb1, 0x43, 0x48, 0x5d, 0xfd, + 0x08, 0x7f, 0x78, 0xf2, 0x04, 0x55, 0xd4, 0x1c, 0xec, 0xab, 0x96, 0x0e, 0x11, 0x02, 0x69, 0x0d, + 0x19, 0x81, 0x0f, 0x29, 0x75, 0x25, 0xa5, 0xe2, 0x89, 0x41, 0x4f, 0x5d, 0xc9, 0xee, 0xe5, 0xcb, + 0xfe, 0x3f, 0x2f, 0x9e, 0x06, 0x73 }; const char* shaderSource() { diff --git a/src/mbgl/programs/gl/shader_source.hpp b/src/mbgl/programs/gl/shader_source.hpp index f6de8a56cc..1a5fbddae3 100644 --- a/src/mbgl/programs/gl/shader_source.hpp +++ b/src/mbgl/programs/gl/shader_source.hpp @@ -8,6 +8,9 @@ namespace gl { const char* shaderSource(); +template <typename> +struct ShaderSource; + } // namespace gl } // namespace programs } // namespace mbgl diff --git a/src/mbgl/programs/gl/shaders.cpp b/src/mbgl/programs/gl/shaders.cpp index 3cc33992de..6fb4d70db9 100644 --- a/src/mbgl/programs/gl/shaders.cpp +++ b/src/mbgl/programs/gl/shaders.cpp @@ -1,4 +1,5 @@ #include <mbgl/programs/gl/shaders.hpp> +#include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/program_parameters.hpp> #include <mbgl/util/string.hpp> @@ -9,20 +10,17 @@ namespace mbgl { namespace programs { namespace gl { -std::string fragmentSource(const ProgramParameters& parameters, const char* fragmentSource) { - return parameters.getDefines() + fragmentShaderPrelude + fragmentSource; -} - -std::string vertexSource(const ProgramParameters& parameters, const char* vertexSource) { - return parameters.getDefines() + vertexShaderPrelude + vertexSource; -} - -std::string programIdentifier(const std::string& vertexSource, const std::string& fragmentSource) { +std::string programIdentifier(const std::string& defines1, + const std::string& defines2, + const uint8_t hash1[8], + const uint8_t hash2[8]) { std::string result; - result.reserve((sizeof(size_t) * 2) * 2 + 2); // 2 size_t hex values + "v2" - result += util::toHex(std::hash<std::string>()(vertexSource)); - result += util::toHex(std::hash<std::string>()(fragmentSource)); - result += "v3"; + result.reserve(8 + 8 + (sizeof(size_t) * 2) * 2 + 2); + result.append(util::toHex(std::hash<std::string>()(defines1))); + result.append(util::toHex(std::hash<std::string>()(defines2))); + result.append(hash1, hash2 + 8); + result.append(hash2, hash2 + 8); + result.append("v3"); return result; } diff --git a/src/mbgl/programs/gl/shaders.hpp b/src/mbgl/programs/gl/shaders.hpp index 5278ea54da..46a87f4af8 100644 --- a/src/mbgl/programs/gl/shaders.hpp +++ b/src/mbgl/programs/gl/shaders.hpp @@ -9,9 +9,10 @@ class ProgramParameters; namespace programs { namespace gl { -std::string fragmentSource(const ProgramParameters&, const char* fragmentSource); -std::string vertexSource(const ProgramParameters&, const char* vertexSource); -std::string programIdentifier(const std::string& vertexSource, const std::string& fragmentSource); +std::string programIdentifier(const std::string& defines1, + const std::string& defines2, + const uint8_t hash1[8], + const uint8_t hash2[8]); } // namespace gl } // namespace programs diff --git a/src/mbgl/programs/gl/symbol_icon.cpp b/src/mbgl/programs/gl/symbol_icon.cpp index 733d3b7ebd..6cb2b88543 100644 --- a/src/mbgl/programs/gl/symbol_icon.cpp +++ b/src/mbgl/programs/gl/symbol_icon.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/symbol_icon_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolIconProgram> { + static constexpr const char* name = "symbol_icon"; + static constexpr const uint8_t hash[8] = { 0x96, 0x0c, 0xef, 0xec, 0x37, 0x23, 0xf9, 0xb1 }; + static constexpr const auto vertexOffset = 50000; + static constexpr const auto fragmentOffset = 52654; +}; + +constexpr const char* ShaderSource<SymbolIconProgram>::name; +constexpr const uint8_t ShaderSource<SymbolIconProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<SymbolIconProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<SymbolIconProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "symbol_icon", - programs::gl::shaderSource() + 50000, programs::gl::shaderSource() + 52654); + return std::make_unique<gl::Program<SymbolIconProgram>>(programParameters); } } // namespace gfx @@ -39,7 +58,7 @@ uniform float u_fade_change; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -62,7 +81,7 @@ varying float v_fade_opacity; void main() { #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif diff --git a/src/mbgl/programs/gl/symbol_sdf_icon.cpp b/src/mbgl/programs/gl/symbol_sdf_icon.cpp index ef3ecd138c..d98554099f 100644 --- a/src/mbgl/programs/gl/symbol_sdf_icon.cpp +++ b/src/mbgl/programs/gl/symbol_sdf_icon.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/symbol_sdf_icon_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolSDFIconProgram> { + static constexpr const char* name = "symbol_sdf_icon"; + static constexpr const uint8_t hash[8] = { 0x13, 0xfc, 0x05, 0x2a, 0xd1, 0x93, 0xfb, 0x7d }; + static constexpr const auto vertexOffset = 53059; + static constexpr const auto fragmentOffset = 57099; +}; + +constexpr const char* ShaderSource<SymbolSDFIconProgram>::name; +constexpr const uint8_t ShaderSource<SymbolSDFIconProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<SymbolSDFIconProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<SymbolSDFIconProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "symbol_sdf_icon", - programs::gl::shaderSource() + 53059, programs::gl::shaderSource() + 57099); + return std::make_unique<gl::Program<SymbolSDFIconProgram>>(programParameters); } } // namespace gfx @@ -41,7 +60,7 @@ uniform highp float u_size; // used when size is both zoom and feature constant #ifndef HAS_UNIFORM_u_fill_color -uniform lowp float a_fill_color_t; +uniform lowp float u_fill_color_t; attribute highp vec4 a_fill_color; varying highp vec4 fill_color; #else @@ -50,7 +69,7 @@ uniform highp vec4 u_fill_color; #ifndef HAS_UNIFORM_u_halo_color -uniform lowp float a_halo_color_t; +uniform lowp float u_halo_color_t; attribute highp vec4 a_halo_color; varying highp vec4 halo_color; #else @@ -59,7 +78,7 @@ uniform highp vec4 u_halo_color; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -68,7 +87,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_halo_width -uniform lowp float a_halo_width_t; +uniform lowp float u_halo_width_t; attribute lowp vec2 a_halo_width; varying lowp float halo_width; #else @@ -77,7 +96,7 @@ uniform lowp float u_halo_width; #ifndef HAS_UNIFORM_u_halo_blur -uniform lowp float a_halo_blur_t; +uniform lowp float u_halo_blur_t; attribute lowp vec2 a_halo_blur; varying lowp float halo_blur; #else @@ -105,35 +124,35 @@ varying vec3 v_data1; void main() { #ifndef HAS_UNIFORM_u_fill_color - fill_color = unpack_mix_color(a_fill_color, a_fill_color_t); + fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); #else highp vec4 fill_color = u_fill_color; #endif #ifndef HAS_UNIFORM_u_halo_color - halo_color = unpack_mix_color(a_halo_color, a_halo_color_t); + halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); #else highp vec4 halo_color = u_halo_color; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_halo_width - halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); + halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); #else lowp float halo_width = u_halo_width; #endif #ifndef HAS_UNIFORM_u_halo_blur - halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); + halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); #else lowp float halo_blur = u_halo_blur; #endif diff --git a/src/mbgl/programs/gl/symbol_sdf_text.cpp b/src/mbgl/programs/gl/symbol_sdf_text.cpp index a0d810d1ce..81f3729d92 100644 --- a/src/mbgl/programs/gl/symbol_sdf_text.cpp +++ b/src/mbgl/programs/gl/symbol_sdf_text.cpp @@ -1,18 +1,37 @@ // NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. #include <mbgl/programs/symbol_sdf_text_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> #include <mbgl/programs/gl/shader_source.hpp> #include <mbgl/gl/program.hpp> namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolSDFTextProgram> { + static constexpr const char* name = "symbol_sdf_text"; + static constexpr const uint8_t hash[8] = { 0x13, 0xfc, 0x05, 0x2a, 0xd1, 0x93, 0xfb, 0x7d }; + static constexpr const auto vertexOffset = 53059; + static constexpr const auto fragmentOffset = 57099; +}; + +constexpr const char* ShaderSource<SymbolSDFTextProgram>::name; +constexpr const uint8_t ShaderSource<SymbolSDFTextProgram>::hash[8]; + +} // namespace gl +} // namespace programs + namespace gfx { template <> std::unique_ptr<Program<SymbolSDFTextProgram>> Context::createProgram<gl::Context>(const ProgramParameters& programParameters) { - return gl::Program<SymbolSDFTextProgram>::createProgram( - reinterpret_cast<gl::Context&>(*this), programParameters, "symbol_sdf_text", - programs::gl::shaderSource() + 53059, programs::gl::shaderSource() + 57099); + return std::make_unique<gl::Program<SymbolSDFTextProgram>>(programParameters); } } // namespace gfx @@ -41,7 +60,7 @@ uniform highp float u_size; // used when size is both zoom and feature constant #ifndef HAS_UNIFORM_u_fill_color -uniform lowp float a_fill_color_t; +uniform lowp float u_fill_color_t; attribute highp vec4 a_fill_color; varying highp vec4 fill_color; #else @@ -50,7 +69,7 @@ uniform highp vec4 u_fill_color; #ifndef HAS_UNIFORM_u_halo_color -uniform lowp float a_halo_color_t; +uniform lowp float u_halo_color_t; attribute highp vec4 a_halo_color; varying highp vec4 halo_color; #else @@ -59,7 +78,7 @@ uniform highp vec4 u_halo_color; #ifndef HAS_UNIFORM_u_opacity -uniform lowp float a_opacity_t; +uniform lowp float u_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; #else @@ -68,7 +87,7 @@ uniform lowp float u_opacity; #ifndef HAS_UNIFORM_u_halo_width -uniform lowp float a_halo_width_t; +uniform lowp float u_halo_width_t; attribute lowp vec2 a_halo_width; varying lowp float halo_width; #else @@ -77,7 +96,7 @@ uniform lowp float u_halo_width; #ifndef HAS_UNIFORM_u_halo_blur -uniform lowp float a_halo_blur_t; +uniform lowp float u_halo_blur_t; attribute lowp vec2 a_halo_blur; varying lowp float halo_blur; #else @@ -105,35 +124,35 @@ varying vec3 v_data1; void main() { #ifndef HAS_UNIFORM_u_fill_color - fill_color = unpack_mix_color(a_fill_color, a_fill_color_t); + fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); #else highp vec4 fill_color = u_fill_color; #endif #ifndef HAS_UNIFORM_u_halo_color - halo_color = unpack_mix_color(a_halo_color, a_halo_color_t); + halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); #else highp vec4 halo_color = u_halo_color; #endif #ifndef HAS_UNIFORM_u_opacity - opacity = unpack_mix_vec2(a_opacity, a_opacity_t); + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); #else lowp float opacity = u_opacity; #endif #ifndef HAS_UNIFORM_u_halo_width - halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t); + halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); #else lowp float halo_width = u_halo_width; #endif #ifndef HAS_UNIFORM_u_halo_blur - halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t); + halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); #else lowp float halo_blur = u_halo_blur; #endif diff --git a/src/mbgl/programs/heatmap_program.hpp b/src/mbgl/programs/heatmap_program.hpp index 9563dd8d1b..537a9e9565 100644 --- a/src/mbgl/programs/heatmap_program.hpp +++ b/src/mbgl/programs/heatmap_program.hpp @@ -10,18 +10,18 @@ namespace mbgl { namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(float, u_intensity); +MBGL_DEFINE_UNIFORM_SCALAR(float, intensity); } // namespace uniforms class HeatmapProgram : public Program< HeatmapProgram, gfx::PrimitiveType::Triangle, TypeList< - attributes::a_pos>, + attributes::pos>, TypeList< - uniforms::u_intensity, - uniforms::u_matrix, - uniforms::heatmap::u_extrude_scale>, + uniforms::intensity, + uniforms::matrix, + uniforms::heatmap::extrude_scale>, TypeList<>, style::HeatmapPaintProperties> { @@ -52,7 +52,7 @@ public: HeatmapLayerPrograms(gfx::Context& context, const ProgramParameters& programParameters) : heatmap(context, programParameters), heatmapTexture(context, programParameters) {} - ProgramMap<HeatmapProgram> heatmap; + HeatmapProgram heatmap; HeatmapTextureProgram heatmapTexture; }; diff --git a/src/mbgl/programs/heatmap_texture_program.hpp b/src/mbgl/programs/heatmap_texture_program.hpp index 954e03f9b6..6762f8c7f4 100644 --- a/src/mbgl/programs/heatmap_texture_program.hpp +++ b/src/mbgl/programs/heatmap_texture_program.hpp @@ -12,14 +12,14 @@ namespace mbgl { class HeatmapTextureProgram : public Program< HeatmapTextureProgram, gfx::PrimitiveType::Triangle, - TypeList<attributes::a_pos>, + TypeList<attributes::pos>, TypeList< - uniforms::u_matrix, - uniforms::u_world, - uniforms::u_opacity>, + uniforms::matrix, + uniforms::world, + uniforms::opacity>, TypeList< - textures::u_image, - textures::u_color_ramp>, + textures::image, + textures::color_ramp>, style::Properties<>> { public: using Program::Program; diff --git a/src/mbgl/programs/hillshade_prepare_program.hpp b/src/mbgl/programs/hillshade_prepare_program.hpp index 0243cc1879..2d76145bc3 100644 --- a/src/mbgl/programs/hillshade_prepare_program.hpp +++ b/src/mbgl/programs/hillshade_prepare_program.hpp @@ -9,23 +9,23 @@ namespace mbgl { namespace uniforms { -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_dimension); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_maxzoom); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, dimension); +MBGL_DEFINE_UNIFORM_SCALAR(float, maxzoom); } // namespace uniforms class HillshadePrepareProgram : public Program< HillshadePrepareProgram, gfx::PrimitiveType::Triangle, TypeList< - attributes::a_pos, - attributes::a_texture_pos>, + attributes::pos, + attributes::texture_pos>, TypeList< - uniforms::u_matrix, - uniforms::u_dimension, - uniforms::u_zoom, - uniforms::u_maxzoom>, + uniforms::matrix, + uniforms::dimension, + uniforms::zoom, + uniforms::maxzoom>, TypeList< - textures::u_image>, + textures::image>, style::Properties<>> { public: using Program::Program; diff --git a/src/mbgl/programs/hillshade_program.hpp b/src/mbgl/programs/hillshade_program.hpp index 68d67917df..33f91abef0 100644 --- a/src/mbgl/programs/hillshade_program.hpp +++ b/src/mbgl/programs/hillshade_program.hpp @@ -11,28 +11,28 @@ namespace mbgl { namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_shadow); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_highlight); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_accent); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_light); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_latrange); +MBGL_DEFINE_UNIFORM_SCALAR(Color, shadow); +MBGL_DEFINE_UNIFORM_SCALAR(Color, highlight); +MBGL_DEFINE_UNIFORM_SCALAR(Color, accent); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, light); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, latrange); } // namespace uniforms class HillshadeProgram : public Program< HillshadeProgram, gfx::PrimitiveType::Triangle, TypeList< - attributes::a_pos, - attributes::a_texture_pos>, + attributes::pos, + attributes::texture_pos>, TypeList< - uniforms::u_matrix, - uniforms::u_highlight, - uniforms::u_shadow, - uniforms::u_accent, - uniforms::u_light, - uniforms::u_latrange>, + uniforms::matrix, + uniforms::highlight, + uniforms::shadow, + uniforms::accent, + uniforms::light, + uniforms::latrange>, TypeList< - textures::u_image>, + textures::image>, style::HillshadePaintProperties>{ public: using Program::Program; diff --git a/src/mbgl/programs/line_program.cpp b/src/mbgl/programs/line_program.cpp index 74a1ba3162..9428b5d9d6 100644 --- a/src/mbgl/programs/line_program.cpp +++ b/src/mbgl/programs/line_program.cpp @@ -19,26 +19,26 @@ using namespace style; static_assert(sizeof(LineLayoutVertex) == 12, "expected LineLayoutVertex size"); template <class Values, class...Args> -Values makeValues(const RenderLinePaintProperties::PossiblyEvaluated& properties, +Values makeValues(const style::LinePaintProperties::PossiblyEvaluated& properties, const RenderTile& tile, const TransformState& state, const std::array<float, 2>& pixelsToGLUnits, Args&&... args) { return Values { - uniforms::u_matrix::Value( + uniforms::matrix::Value( tile.translatedMatrix(properties.get<LineTranslate>(), properties.get<LineTranslateAnchor>(), state) ), - 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]} }), + uniforms::ratio::Value( 1.0f / tile.id.pixelsToTileUnits(1.0, state.getZoom()) ), + uniforms::gl_units_to_pixels::Value({ {1.0f / pixelsToGLUnits[0], 1.0f / pixelsToGLUnits[1]} }), std::forward<Args>(args)... }; } LineProgram::LayoutUniformValues -LineProgram::layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated& properties, +LineProgram::layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated& properties, const RenderTile& tile, const TransformState& state, const std::array<float, 2>& pixelsToGLUnits) { @@ -51,7 +51,7 @@ LineProgram::layoutUniformValues(const RenderLinePaintProperties::PossiblyEvalua } LineSDFProgram::LayoutUniformValues -LineSDFProgram::layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated& properties, +LineSDFProgram::layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated& properties, float pixelRatio, const RenderTile& tile, const TransformState& state, @@ -78,17 +78,17 @@ LineSDFProgram::layoutUniformValues(const RenderLinePaintProperties::PossiblyEva tile, state, pixelsToGLUnits, - uniforms::u_patternscale_a::Value( scaleA ), - uniforms::u_patternscale_b::Value( scaleB ), - uniforms::u_tex_y_a::Value( posA.y ), - uniforms::u_tex_y_b::Value( posB.y ), - uniforms::u_mix::Value( crossfade.t ), - uniforms::u_sdfgamma::Value( atlasWidth / (std::min(widthA, widthB) * 256.0f * pixelRatio) / 2.0f ) + uniforms::patternscale_a::Value( scaleA ), + uniforms::patternscale_b::Value( scaleB ), + uniforms::tex_y_a::Value( posA.y ), + uniforms::tex_y_b::Value( posB.y ), + uniforms::mix::Value( crossfade.t ), + uniforms::sdfgamma::Value( atlasWidth / (std::min(widthA, widthB) * 256.0f * pixelRatio) / 2.0f ) ); } LinePatternProgram::LayoutUniformValues LinePatternProgram::layoutUniformValues( - const RenderLinePaintProperties::PossiblyEvaluated& properties, + const style::LinePaintProperties::PossiblyEvaluated& properties, const RenderTile& tile, const TransformState& state, const std::array<float, 2>& pixelsToGLUnits, @@ -103,14 +103,14 @@ LinePatternProgram::LayoutUniformValues LinePatternProgram::layoutUniformValues( tile, state, pixelsToGLUnits, - uniforms::u_scale::Value ({ {pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale} }), - uniforms::u_texsize::Value( atlasSize ), - uniforms::u_fade::Value( crossfade.t ) + uniforms::scale::Value ({ {pixelRatio, tileRatio, crossfade.fromScale, crossfade.toScale} }), + uniforms::texsize::Value( atlasSize ), + uniforms::fade::Value( crossfade.t ) ); } LineGradientProgram::LayoutUniformValues LineGradientProgram::layoutUniformValues( - const RenderLinePaintProperties::PossiblyEvaluated& properties, + const style::LinePaintProperties::PossiblyEvaluated& properties, const RenderTile& tile, const TransformState& state, const std::array<float, 2>& pixelsToGLUnits) { diff --git a/src/mbgl/programs/line_program.hpp b/src/mbgl/programs/line_program.hpp index 05546e3cbe..ed149abb33 100644 --- a/src/mbgl/programs/line_program.hpp +++ b/src/mbgl/programs/line_program.hpp @@ -17,29 +17,29 @@ class LinePatternPos; class ImagePosition; namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(float, u_ratio); -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); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_a); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_patternscale_b); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_gl_units_to_pixels); +MBGL_DEFINE_UNIFORM_SCALAR(float, ratio); +MBGL_DEFINE_UNIFORM_SCALAR(float, tex_y_a); +MBGL_DEFINE_UNIFORM_SCALAR(float, tex_y_b); +MBGL_DEFINE_UNIFORM_SCALAR(float, sdfgamma); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, patternscale_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, patternscale_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, gl_units_to_pixels); } // namespace uniforms using LineLayoutAttributes = TypeList< - attributes::a_pos_normal, - attributes::a_data<uint8_t, 4>>; + attributes::pos_normal, + attributes::data<uint8_t, 4>>; class LineProgram : public Program< LineProgram, gfx::PrimitiveType::Triangle, LineLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_ratio, - uniforms::u_gl_units_to_pixels>, + uniforms::matrix, + uniforms::ratio, + uniforms::gl_units_to_pixels>, TypeList<>, - RenderLinePaintProperties> + style::LinePaintProperties> { public: using Program::Program; @@ -90,7 +90,7 @@ public: static const int8_t extrudeScale = 63; static LayoutUniformValues - layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated&, + layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated&, const RenderTile&, const TransformState&, const std::array<float, 2>& pixelsToGLUnits); @@ -101,21 +101,21 @@ class LinePatternProgram : public Program< gfx::PrimitiveType::Triangle, LineLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_ratio, - uniforms::u_gl_units_to_pixels, - uniforms::u_scale, - uniforms::u_texsize, - uniforms::u_fade>, + uniforms::matrix, + uniforms::ratio, + uniforms::gl_units_to_pixels, + uniforms::scale, + uniforms::texsize, + uniforms::fade>, TypeList< - textures::u_image>, - RenderLinePaintProperties> + textures::image>, + style::LinePaintProperties> { public: using Program::Program; static LayoutUniformValues - layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated&, + layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated&, const RenderTile&, const TransformState&, const std::array<float, 2>& pixelsToGLUnits, @@ -129,24 +129,24 @@ class LineSDFProgram : public Program< gfx::PrimitiveType::Triangle, LineLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_ratio, - uniforms::u_gl_units_to_pixels, - 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::matrix, + uniforms::ratio, + uniforms::gl_units_to_pixels, + uniforms::patternscale_a, + uniforms::patternscale_b, + uniforms::tex_y_a, + uniforms::tex_y_b, + uniforms::mix, + uniforms::sdfgamma>, TypeList< - textures::u_image>, - RenderLinePaintProperties> + textures::image>, + style::LinePaintProperties> { public: using Program::Program; static LayoutUniformValues - layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated&, + layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated&, float pixelRatio, const RenderTile&, const TransformState&, @@ -162,18 +162,18 @@ class LineGradientProgram : public Program< gfx::PrimitiveType::Triangle, LineLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_ratio, - uniforms::u_gl_units_to_pixels>, + uniforms::matrix, + uniforms::ratio, + uniforms::gl_units_to_pixels>, TypeList< - textures::u_image>, - RenderLinePaintProperties> + textures::image>, + style::LinePaintProperties> { public: using Program::Program; static LayoutUniformValues - layoutUniformValues(const RenderLinePaintProperties::PossiblyEvaluated&, + layoutUniformValues(const style::LinePaintProperties::PossiblyEvaluated&, const RenderTile&, const TransformState&, const std::array<float, 2>& pixelsToGLUnits); @@ -189,10 +189,10 @@ public: lineGradient(context, programParameters), lineSDF(context, programParameters), linePattern(context, programParameters) {} - ProgramMap<LineProgram> line; - ProgramMap<LineGradientProgram> lineGradient; - ProgramMap<LineSDFProgram> lineSDF; - ProgramMap<LinePatternProgram> linePattern; + LineProgram line; + LineGradientProgram lineGradient; + LineSDFProgram lineSDF; + LinePatternProgram linePattern; }; } // namespace mbgl diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 240da22b4f..e4d2af95f8 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -109,36 +109,6 @@ public: } }; -template <class Program> -class ProgramMap { -public: - using PaintProperties = typename Program::PaintProperties; - using Binders = typename Program::Binders; - using Bitset = typename Binders::Bitset; - - ProgramMap(gfx::Context& context_, ProgramParameters parameters_) - : context(context_), - parameters(std::move(parameters_)) { - } - - Program& get(const typename PaintProperties::PossiblyEvaluated& currentProperties) { - Bitset bits = Binders::constants(currentProperties); - auto it = programs.find(bits); - if (it != programs.end()) { - return it->second; - } - return programs.emplace(std::piecewise_construct, - std::forward_as_tuple(bits), - std::forward_as_tuple(context, - parameters.withAdditionalDefines(Binders::defines(currentProperties)))).first->second; - } - -private: - gfx::Context& context; - ProgramParameters parameters; - std::unordered_map<Bitset, Program> programs; -}; - class LayerTypePrograms { public: virtual ~LayerTypePrograms() = default; diff --git a/src/mbgl/programs/program_parameters.cpp b/src/mbgl/programs/program_parameters.cpp index 6b6c2bb2fe..e692b74e0e 100644 --- a/src/mbgl/programs/program_parameters.cpp +++ b/src/mbgl/programs/program_parameters.cpp @@ -40,13 +40,4 @@ optional<std::string> ProgramParameters::cachePath(const char* name) const { } } -ProgramParameters ProgramParameters::withAdditionalDefines(const std::vector<std::string>& additionalDefines) const { - ProgramParameters result(*this); - for (const auto& define : additionalDefines) { - result.defines += define; - result.defines += "\n"; - } - return result; -} - } // namespace mbgl diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp index e94e61c217..71ad454399 100644 --- a/src/mbgl/programs/program_parameters.hpp +++ b/src/mbgl/programs/program_parameters.hpp @@ -3,7 +3,6 @@ #include <mbgl/util/optional.hpp> #include <string> -#include <vector> namespace mbgl { @@ -14,8 +13,6 @@ public: const std::string& getDefines() const; optional<std::string> cachePath(const char* name) const; - ProgramParameters withAdditionalDefines(const std::vector<std::string>& defines) const; - private: std::string defines; optional<std::string> cacheDir; diff --git a/src/mbgl/programs/raster_program.hpp b/src/mbgl/programs/raster_program.hpp index 55f1fb0a2e..e84ada0bdc 100644 --- a/src/mbgl/programs/raster_program.hpp +++ b/src/mbgl/programs/raster_program.hpp @@ -10,38 +10,38 @@ namespace mbgl { namespace uniforms { -MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade_t); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_buffer_scale); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_low); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_brightness_high); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_saturation_factor); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_contrast_factor); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_scale_parent); -MBGL_DEFINE_UNIFORM_VECTOR(float, 3, u_spin_weights); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_tl_parent); +MBGL_DEFINE_UNIFORM_SCALAR(float, fade_t); +MBGL_DEFINE_UNIFORM_SCALAR(float, buffer_scale); +MBGL_DEFINE_UNIFORM_SCALAR(float, brightness_low); +MBGL_DEFINE_UNIFORM_SCALAR(float, brightness_high); +MBGL_DEFINE_UNIFORM_SCALAR(float, saturation_factor); +MBGL_DEFINE_UNIFORM_SCALAR(float, contrast_factor); +MBGL_DEFINE_UNIFORM_SCALAR(float, scale_parent); +MBGL_DEFINE_UNIFORM_VECTOR(float, 3, spin_weights); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, tl_parent); } // namespace uniforms class RasterProgram : public Program< RasterProgram, gfx::PrimitiveType::Triangle, TypeList< - attributes::a_pos, - attributes::a_texture_pos>, + attributes::pos, + attributes::texture_pos>, TypeList< - uniforms::u_matrix, - uniforms::u_opacity, - uniforms::u_fade_t, - uniforms::u_brightness_low, - uniforms::u_brightness_high, - uniforms::u_saturation_factor, - uniforms::u_contrast_factor, - uniforms::u_spin_weights, - uniforms::u_buffer_scale, - uniforms::u_scale_parent, - uniforms::u_tl_parent>, + uniforms::matrix, + uniforms::opacity, + uniforms::fade_t, + uniforms::brightness_low, + uniforms::brightness_high, + uniforms::saturation_factor, + uniforms::contrast_factor, + uniforms::spin_weights, + uniforms::buffer_scale, + uniforms::scale_parent, + uniforms::tl_parent>, TypeList< - textures::u_image0, - textures::u_image1>, + textures::image0, + textures::image1>, style::RasterPaintProperties> { public: diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 2300dedff3..d6a7a10368 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -42,6 +42,7 @@ std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom, template <class Values, class...Args> Values makeValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -71,7 +72,7 @@ Values makeValues(const bool isText, const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine; mat4 labelPlaneMatrix; - if (alongLine) { + if (alongLine || (isText && hasVariablePacement)) { // For labels that follow lines the first part of the projection is handled on the cpu. // Pass an identity matrix because no transformation needs to be done in the vertex shader. matrix::identity(labelPlaneMatrix); @@ -82,30 +83,31 @@ Values makeValues(const bool isText, mat4 glCoordMatrix = getGlCoordMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits); return Values { - uniforms::u_matrix::Value( tile.translatedMatrix(values.translate, + uniforms::matrix::Value( tile.translatedMatrix(values.translate, values.translateAnchor, state) ), - uniforms::u_label_plane_matrix::Value(labelPlaneMatrix), - uniforms::u_gl_coord_matrix::Value( tile.translateVtxMatrix(glCoordMatrix, + uniforms::label_plane_matrix::Value(labelPlaneMatrix), + uniforms::gl_coord_matrix::Value( tile.translateVtxMatrix(glCoordMatrix, values.translate, values.translateAnchor, state, true) ), - uniforms::u_extrude_scale::Value( extrudeScale ), - uniforms::u_texsize::Value( texsize ), - uniforms::u_fade_change::Value( symbolFadeChange ), - uniforms::u_is_text::Value( isText ), - uniforms::u_camera_to_center_distance::Value( state.getCameraToCenterDistance() ), - uniforms::u_pitch::Value( state.getPitch() ), - uniforms::u_pitch_with_map::Value( pitchWithMap ), - uniforms::u_rotate_symbol::Value( rotateInShader ), - uniforms::u_aspect_ratio::Value( state.getSize().aspectRatio() ), + uniforms::extrude_scale::Value( extrudeScale ), + uniforms::texsize::Value( texsize ), + uniforms::fade_change::Value( symbolFadeChange ), + uniforms::is_text::Value( isText ), + uniforms::camera_to_center_distance::Value( state.getCameraToCenterDistance() ), + uniforms::pitch::Value( state.getPitch() ), + uniforms::pitch_with_map::Value( pitchWithMap ), + uniforms::rotate_symbol::Value( rotateInShader ), + uniforms::aspect_ratio::Value( state.getSize().aspectRatio() ), std::forward<Args>(args)... }; } SymbolIconProgram::LayoutUniformValues SymbolIconProgram::layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -115,6 +117,7 @@ SymbolIconProgram::layoutUniformValues(const bool isText, const float symbolFadeChange) { return makeValues<SymbolIconProgram::LayoutUniformValues>( isText, + hasVariablePacement, values, texsize, pixelsToGLUnits, @@ -128,6 +131,7 @@ SymbolIconProgram::layoutUniformValues(const bool isText, template <class Name, class PaintProperties> typename SymbolSDFProgram<Name, PaintProperties>::LayoutUniformValues SymbolSDFProgram<Name, PaintProperties>::layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -142,6 +146,7 @@ SymbolSDFProgram<Name, PaintProperties>::layoutUniformValues(const bool isText, return makeValues<SymbolSDFProgram<Name, PaintProperties>::LayoutUniformValues>( isText, + hasVariablePacement, values, texsize, pixelsToGLUnits, @@ -149,8 +154,8 @@ SymbolSDFProgram<Name, PaintProperties>::layoutUniformValues(const bool isText, tile, state, symbolFadeChange, - uniforms::u_gamma_scale::Value( gammaScale ), - uniforms::u_is_halo::Value( part == SymbolSDFPart::Halo ) + uniforms::gamma_scale::Value( gammaScale ), + uniforms::is_halo::Value( part == SymbolSDFPart::Halo ) ); } diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 383f5162d8..d640eb74da 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -1,6 +1,5 @@ #pragma once -#include <mbgl/gl/program.hpp> #include <mbgl/math/clamp.hpp> #include <mbgl/util/interpolate.hpp> @@ -29,27 +28,27 @@ class RenderTile; class TransformState; namespace uniforms { -MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_gl_coord_matrix); -MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_label_plane_matrix); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale); - -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_text); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, gl_coord_matrix); +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, label_plane_matrix); +MBGL_DEFINE_UNIFORM_SCALAR(bool, is_halo); +MBGL_DEFINE_UNIFORM_SCALAR(float, gamma_scale); + +MBGL_DEFINE_UNIFORM_SCALAR(bool, is_text); +MBGL_DEFINE_UNIFORM_SCALAR(bool, is_size_zoom_constant); +MBGL_DEFINE_UNIFORM_SCALAR(bool, is_size_feature_constant); +MBGL_DEFINE_UNIFORM_SCALAR(float, size_t); +MBGL_DEFINE_UNIFORM_SCALAR(float, size); +MBGL_DEFINE_UNIFORM_SCALAR(bool, rotate_symbol); +MBGL_DEFINE_UNIFORM_SCALAR(float, aspect_ratio); } // namespace uniforms using SymbolLayoutAttributes = TypeList< - attributes::a_pos_offset, - attributes::a_data<uint16_t, 4>>; + attributes::pos_offset, + attributes::data<uint16_t, 4>>; -using SymbolDynamicLayoutAttributes = TypeList<attributes::a_projected_pos>; +using SymbolDynamicLayoutAttributes = TypeList<attributes::projected_pos>; -using SymbolOpacityAttributes = TypeList<attributes::a_fade_opacity>; +using SymbolOpacityAttributes = TypeList<attributes::fade_opacity>; struct ZoomEvaluatedSize { bool isZoomConstant; @@ -67,10 +66,10 @@ public: virtual ~SymbolSizeBinder() = default; using UniformList = TypeList< - uniforms::u_is_size_zoom_constant, - uniforms::u_is_size_feature_constant, - uniforms::u_size_t, - uniforms::u_size>; + uniforms::is_size_zoom_constant, + uniforms::is_size_feature_constant, + uniforms::size_t, + uniforms::size>; using UniformValues = gfx::UniformValues<UniformList>; static std::unique_ptr<SymbolSizeBinder> create(const float tileZoom, @@ -83,10 +82,10 @@ public: UniformValues uniformValues(float currentZoom) const { const ZoomEvaluatedSize u = evaluateForZoom(currentZoom); return UniformValues { - uniforms::u_is_size_zoom_constant::Value( u.isZoomConstant ), - uniforms::u_is_size_feature_constant::Value( u.isFeatureConstant), - uniforms::u_size_t::Value( u.sizeT ), - uniforms::u_size::Value( u.size ) + uniforms::is_size_zoom_constant::Value( u.isZoomConstant ), + uniforms::is_size_feature_constant::Value( u.isFeatureConstant), + uniforms::size_t::Value( u.sizeT ), + uniforms::size::Value( u.size ) }; } }; @@ -348,26 +347,27 @@ class SymbolIconProgram : public SymbolProgram< gfx::PrimitiveType::Triangle, SymbolLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_label_plane_matrix, - uniforms::u_gl_coord_matrix, - uniforms::u_extrude_scale, - uniforms::u_texsize, - uniforms::u_fade_change, - uniforms::u_is_text, - uniforms::u_camera_to_center_distance, - uniforms::u_pitch, - uniforms::u_pitch_with_map, - uniforms::u_rotate_symbol, - uniforms::u_aspect_ratio>, + uniforms::matrix, + uniforms::label_plane_matrix, + uniforms::gl_coord_matrix, + uniforms::extrude_scale, + uniforms::texsize, + uniforms::fade_change, + uniforms::is_text, + uniforms::camera_to_center_distance, + uniforms::pitch, + uniforms::pitch_with_map, + uniforms::rotate_symbol, + uniforms::aspect_ratio>, TypeList< - textures::u_texture>, + textures::texture>, style::IconPaintProperties> { public: using SymbolProgram::SymbolProgram; static LayoutUniformValues layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -388,22 +388,22 @@ class SymbolSDFProgram : public SymbolProgram< gfx::PrimitiveType::Triangle, SymbolLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_label_plane_matrix, - uniforms::u_gl_coord_matrix, - uniforms::u_extrude_scale, - uniforms::u_texsize, - uniforms::u_fade_change, - uniforms::u_is_text, - uniforms::u_camera_to_center_distance, - uniforms::u_pitch, - uniforms::u_pitch_with_map, - uniforms::u_rotate_symbol, - uniforms::u_aspect_ratio, - uniforms::u_gamma_scale, - uniforms::u_is_halo>, + uniforms::matrix, + uniforms::label_plane_matrix, + uniforms::gl_coord_matrix, + uniforms::extrude_scale, + uniforms::texsize, + uniforms::fade_change, + uniforms::is_text, + uniforms::camera_to_center_distance, + uniforms::pitch, + uniforms::pitch_with_map, + uniforms::rotate_symbol, + uniforms::aspect_ratio, + uniforms::gamma_scale, + uniforms::is_halo>, TypeList< - textures::u_texture>, + textures::texture>, PaintProperties> { public: @@ -412,22 +412,22 @@ public: gfx::PrimitiveType::Triangle, SymbolLayoutAttributes, TypeList< - uniforms::u_matrix, - uniforms::u_label_plane_matrix, - uniforms::u_gl_coord_matrix, - uniforms::u_extrude_scale, - uniforms::u_texsize, - uniforms::u_fade_change, - uniforms::u_is_text, - uniforms::u_camera_to_center_distance, - uniforms::u_pitch, - uniforms::u_pitch_with_map, - uniforms::u_rotate_symbol, - uniforms::u_aspect_ratio, - uniforms::u_gamma_scale, - uniforms::u_is_halo>, + uniforms::matrix, + uniforms::label_plane_matrix, + uniforms::gl_coord_matrix, + uniforms::extrude_scale, + uniforms::texsize, + uniforms::fade_change, + uniforms::is_text, + uniforms::camera_to_center_distance, + uniforms::pitch, + uniforms::pitch_with_map, + uniforms::rotate_symbol, + uniforms::aspect_ratio, + uniforms::gamma_scale, + uniforms::is_halo>, TypeList< - textures::u_texture>, + textures::texture>, PaintProperties>; using LayoutUniformValues = typename BaseProgram::LayoutUniformValues; @@ -437,6 +437,7 @@ public: using BaseProgram::BaseProgram; static LayoutUniformValues layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -469,9 +470,9 @@ public: symbolGlyph(context, programParameters), collisionBox(context, programParameters), collisionCircle(context, programParameters) {} - ProgramMap<SymbolIconProgram> symbolIcon; - ProgramMap<SymbolSDFIconProgram> symbolIconSDF; - ProgramMap<SymbolSDFTextProgram> symbolGlyph; + SymbolIconProgram symbolIcon; + SymbolSDFIconProgram symbolIconSDF; + SymbolSDFTextProgram symbolGlyph; CollisionBoxProgram collisionBox; CollisionCircleProgram collisionCircle; }; diff --git a/src/mbgl/programs/textures.hpp b/src/mbgl/programs/textures.hpp index 32bc4a4a35..4c9de53366 100644 --- a/src/mbgl/programs/textures.hpp +++ b/src/mbgl/programs/textures.hpp @@ -5,11 +5,11 @@ namespace mbgl { namespace textures { -MBGL_DEFINE_TEXTURE(u_image); -MBGL_DEFINE_TEXTURE(u_image0); -MBGL_DEFINE_TEXTURE(u_image1); -MBGL_DEFINE_TEXTURE(u_color_ramp); -MBGL_DEFINE_TEXTURE(u_texture); +MBGL_DEFINE_TEXTURE(image); +MBGL_DEFINE_TEXTURE(image0); +MBGL_DEFINE_TEXTURE(image1); +MBGL_DEFINE_TEXTURE(color_ramp); +MBGL_DEFINE_TEXTURE(texture); } // namespace textures } // namespace mbgl diff --git a/src/mbgl/programs/uniforms.hpp b/src/mbgl/programs/uniforms.hpp index 79febf7f73..702b21def9 100644 --- a/src/mbgl/programs/uniforms.hpp +++ b/src/mbgl/programs/uniforms.hpp @@ -9,61 +9,61 @@ namespace uniforms { // Uniforms common to several shaders. -MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_matrix); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_opacity); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_color); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_blur); +MBGL_DEFINE_UNIFORM_MATRIX(double, 4, matrix); +MBGL_DEFINE_UNIFORM_SCALAR(float, opacity); +MBGL_DEFINE_UNIFORM_SCALAR(Color, color); +MBGL_DEFINE_UNIFORM_SCALAR(float, blur); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_zoom); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_collision_y_stretch); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_pitch); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_bearing); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_radius); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_width); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_stroke_color); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_stroke_opacity); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_fill_color); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_halo_color); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_halo_width); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_halo_blur); -MBGL_DEFINE_UNIFORM_SCALAR(Color, u_outline_color); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_height); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_base); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_width); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_floorwidth); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_gapwidth); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_offset); -MBGL_DEFINE_UNIFORM_SCALAR(Size, u_world); -MBGL_DEFINE_UNIFORM_SCALAR(Size, u_texsize); -MBGL_DEFINE_UNIFORM_SCALAR(bool, u_pitch_with_map); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_camera_to_center_distance); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_fade_change); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_weight); +MBGL_DEFINE_UNIFORM_SCALAR(float, zoom); +MBGL_DEFINE_UNIFORM_SCALAR(float, collision_y_stretch); +MBGL_DEFINE_UNIFORM_SCALAR(float, pitch); +MBGL_DEFINE_UNIFORM_SCALAR(float, bearing); +MBGL_DEFINE_UNIFORM_SCALAR(float, radius); +MBGL_DEFINE_UNIFORM_SCALAR(float, stroke_width); +MBGL_DEFINE_UNIFORM_SCALAR(Color, stroke_color); +MBGL_DEFINE_UNIFORM_SCALAR(float, stroke_opacity); +MBGL_DEFINE_UNIFORM_SCALAR(Color, fill_color); +MBGL_DEFINE_UNIFORM_SCALAR(Color, halo_color); +MBGL_DEFINE_UNIFORM_SCALAR(float, halo_width); +MBGL_DEFINE_UNIFORM_SCALAR(float, halo_blur); +MBGL_DEFINE_UNIFORM_SCALAR(Color, outline_color); +MBGL_DEFINE_UNIFORM_SCALAR(float, height); +MBGL_DEFINE_UNIFORM_SCALAR(float, base); +MBGL_DEFINE_UNIFORM_SCALAR(float, width); +MBGL_DEFINE_UNIFORM_SCALAR(float, floorwidth); +MBGL_DEFINE_UNIFORM_SCALAR(float, gapwidth); +MBGL_DEFINE_UNIFORM_SCALAR(float, offset); +MBGL_DEFINE_UNIFORM_SCALAR(Size, world); +MBGL_DEFINE_UNIFORM_SCALAR(Size, texsize); +MBGL_DEFINE_UNIFORM_SCALAR(bool, pitch_with_map); +MBGL_DEFINE_UNIFORM_SCALAR(float, camera_to_center_distance); +MBGL_DEFINE_UNIFORM_SCALAR(float, fade); +MBGL_DEFINE_UNIFORM_SCALAR(float, fade_change); +MBGL_DEFINE_UNIFORM_SCALAR(float, weight); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_extrude_scale); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, extrude_scale); namespace heatmap { -MBGL_DEFINE_UNIFORM_SCALAR(float, u_extrude_scale); +MBGL_DEFINE_UNIFORM_SCALAR(float, extrude_scale); } // namespace heatmap -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 4, u_pattern_from); -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 4, u_pattern_to); -MBGL_DEFINE_UNIFORM_VECTOR(float, 4, u_scale); -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_a); -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_a); -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_tl_b); -MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, u_pattern_br_b); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_a); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pattern_size_b); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_upper); -MBGL_DEFINE_UNIFORM_VECTOR(float, 2, u_pixel_coord_lower); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 4, pattern_from); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 4, pattern_to); +MBGL_DEFINE_UNIFORM_VECTOR(float, 4, scale); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, pattern_tl_a); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, pattern_br_a); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, pattern_tl_b); +MBGL_DEFINE_UNIFORM_VECTOR(uint16_t, 2, pattern_br_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, pattern_size_a); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, pattern_size_b); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, pixel_coord_upper); +MBGL_DEFINE_UNIFORM_VECTOR(float, 2, pixel_coord_lower); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_mix); -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); -MBGL_DEFINE_UNIFORM_SCALAR(float, u_overscale_factor); +MBGL_DEFINE_UNIFORM_SCALAR(float, mix); +MBGL_DEFINE_UNIFORM_SCALAR(float, scale_a); +MBGL_DEFINE_UNIFORM_SCALAR(float, scale_b); +MBGL_DEFINE_UNIFORM_SCALAR(float, tile_units_to_pixels); +MBGL_DEFINE_UNIFORM_SCALAR(float, overscale_factor); } // namespace uniforms } // namespace mbgl diff --git a/src/mbgl/renderer/buckets/line_bucket.cpp b/src/mbgl/renderer/buckets/line_bucket.cpp index 398a0b4c0f..13f575ba38 100644 --- a/src/mbgl/renderer/buckets/line_bucket.cpp +++ b/src/mbgl/renderer/buckets/line_bucket.cpp @@ -11,7 +11,7 @@ namespace mbgl { using namespace style; LineBucket::LineBucket(const style::LineLayoutProperties::PossiblyEvaluated layout_, - std::map<std::string, RenderLinePaintProperties::PossiblyEvaluated> layerPaintProperties, + std::map<std::string, style::LinePaintProperties::PossiblyEvaluated> layerPaintProperties, const float zoom_, const uint32_t overscaling_) : layout(layout_), diff --git a/src/mbgl/renderer/buckets/line_bucket.hpp b/src/mbgl/renderer/buckets/line_bucket.hpp index 6b8d7e786c..7ee8677e50 100644 --- a/src/mbgl/renderer/buckets/line_bucket.hpp +++ b/src/mbgl/renderer/buckets/line_bucket.hpp @@ -20,7 +20,7 @@ public: // These aliases are used by the PatternLayout template using RenderLayerType = RenderLineLayer; - using PossiblyEvaluatedPaintProperties = RenderLinePaintProperties::PossiblyEvaluated; + using PossiblyEvaluatedPaintProperties = style::LinePaintProperties::PossiblyEvaluated; using PossiblyEvaluatedLayoutProperties = style::LineLayoutProperties::PossiblyEvaluated; LineBucket(const PossiblyEvaluatedLayoutProperties layout, diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 9220235f1d..68f683c8d6 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -17,7 +17,8 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo bool iconsNeedLinear_, bool sortFeaturesByY_, const std::string bucketName_, - const std::vector<SymbolInstance>&& symbolInstances_) + const std::vector<SymbolInstance>&& symbolInstances_, + float tilePixelRatio_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()), @@ -25,7 +26,8 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo bucketLeaderID(std::move(bucketName_)), symbolInstances(std::move(symbolInstances_)), textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())), - iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) { + iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())), + tilePixelRatio(tilePixelRatio_) { for (const auto& pair : paintProperties_) { auto layerPaintProperties = pair.second; @@ -218,12 +220,22 @@ void SymbolBucket::sortFeatures(const float angle) { const SymbolInstance& symbolInstance = symbolInstances[i]; featureSortOrder->push_back(symbolInstance.dataFeatureIndex); - if (symbolInstance.placedTextIndex) { - addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]); + if (symbolInstance.placedRightTextIndex) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedRightTextIndex]); } + + if (symbolInstance.placedCenterTextIndex && !symbolInstance.singleLine) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedCenterTextIndex]); + } + + if (symbolInstance.placedLeftTextIndex && !symbolInstance.singleLine) { + addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedLeftTextIndex]); + } + if (symbolInstance.placedVerticalTextIndex) { addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]); } + if (symbolInstance.placedIconIndex) { addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]); } diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index fafa2592fe..f8ffc1a8eb 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -35,6 +35,8 @@ public: std::vector<float> glyphOffsets; bool hidden; size_t vertexStartIndex; + // The crossTileID is only filled/used on the foreground for variable text anchors + uint32_t crossTileID = 0u; }; class SymbolBucket final : public Bucket { @@ -48,7 +50,8 @@ public: bool iconsNeedLinear, bool sortFeaturesByY, const std::string bucketLeaderID, - const std::vector<SymbolInstance>&&); + const std::vector<SymbolInstance>&&, + const float tilePixelRatio); ~SymbolBucket() override; void upload(gfx::Context&) override; @@ -130,6 +133,7 @@ public: optional<gfx::IndexBuffer> indexBuffer; } collisionCircle; + const float tilePixelRatio; uint32_t bucketInstanceId = 0; bool justReloaded = false; optional<bool> hasFormatSectionOverrides_; diff --git a/src/mbgl/renderer/image_atlas.cpp b/src/mbgl/renderer/image_atlas.cpp index b39c788ced..282f135ac9 100644 --- a/src/mbgl/renderer/image_atlas.cpp +++ b/src/mbgl/renderer/image_atlas.cpp @@ -1,4 +1,6 @@ #include <mbgl/renderer/image_atlas.hpp> +#include <mbgl/gfx/context.hpp> +#include <mbgl/renderer/image_manager.hpp> #include <mapbox/shelf-pack.hpp> @@ -6,14 +8,15 @@ namespace mbgl { static constexpr uint32_t padding = 1; -ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image) +ImagePosition::ImagePosition(const mapbox::Bin& bin, const style::Image::Impl& image, uint32_t version_) : pixelRatio(image.pixelRatio), textureRect( bin.x + padding, bin.y + padding, bin.w - padding * 2, bin.h - padding * 2 - ) { + ), + version(version_) { } const mapbox::Bin& _packImage(mapbox::ShelfPack& pack, const style::Image::Impl& image, ImageAtlas& resultImage, ImageType imageType) { @@ -49,7 +52,30 @@ const mapbox::Bin& _packImage(mapbox::ShelfPack& pack, const style::Image::Impl& return bin; } -ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns) { +void ImageAtlas::patchUpdatedImages(gfx::Context& context, gfx::Texture& atlasTexture, const ImageManager& imageManager) { + for (auto& updatedImageVersion : imageManager.updatedImageVersions) { + auto iconPosition = iconPositions.find(updatedImageVersion.first); + if (iconPosition != iconPositions.end()) { + patchUpdatedImage(context, atlasTexture, iconPosition->second, imageManager, updatedImageVersion.first, updatedImageVersion.second); + } + auto patternPosition = patternPositions.find(updatedImageVersion.first); + if (patternPosition != patternPositions.end()) { + patchUpdatedImage(context, atlasTexture, patternPosition->second, imageManager, updatedImageVersion.first, updatedImageVersion.second); + } + } +} + +void ImageAtlas::patchUpdatedImage(gfx::Context& context, gfx::Texture& atlasTexture, ImagePosition& position, const ImageManager& imageManager, const std::string& name, uint16_t version) { + if (position.version == version) return; + + auto updatedImage = imageManager.getImage(name); + if (updatedImage == nullptr) return; + + context.updateTextureSub(atlasTexture, updatedImage->image, position.textureRect.x, position.textureRect.y); + position.version = version; +} + +ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns, const std::unordered_map<std::string, uint32_t>& versionMap) { ImageAtlas result; mapbox::ShelfPack::ShelfPackOptions options; @@ -59,13 +85,17 @@ ImageAtlas makeImageAtlas(const ImageMap& icons, const ImageMap& patterns) { for (const auto& entry : icons) { const style::Image::Impl& image = *entry.second; const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Icon); - result.iconPositions.emplace(image.id, ImagePosition { bin, image }); + auto it = versionMap.find(entry.first); + auto version = it != versionMap.end() ? it->second : 0; + result.iconPositions.emplace(image.id, ImagePosition { bin, image, version }); } for (const auto& entry : patterns) { const style::Image::Impl& image = *entry.second; const mapbox::Bin& bin = _packImage(pack, image, result, ImageType::Pattern); - result.patternPositions.emplace(image.id, ImagePosition { bin, image }); + auto it = versionMap.find(entry.first); + auto version = it != versionMap.end() ? it->second : 0; + result.patternPositions.emplace(image.id, ImagePosition { bin, image, version }); } pack.shrink(); diff --git a/src/mbgl/renderer/image_atlas.hpp b/src/mbgl/renderer/image_atlas.hpp index 3af31a75f8..080a490ab2 100644 --- a/src/mbgl/renderer/image_atlas.hpp +++ b/src/mbgl/renderer/image_atlas.hpp @@ -9,12 +9,20 @@ namespace mbgl { +namespace gfx { + class Texture; + class Context; +} // namespace gfx + +class ImageManager; + class ImagePosition { public: - ImagePosition(const mapbox::Bin&, const style::Image::Impl&); + ImagePosition(const mapbox::Bin&, const style::Image::Impl&, uint32_t version = 0); float pixelRatio; Rect<uint16_t> textureRect; + uint32_t version; std::array<uint16_t, 2> tl() const { return {{ @@ -51,8 +59,12 @@ public: PremultipliedImage image; ImagePositions iconPositions; ImagePositions patternPositions; + + void patchUpdatedImages(gfx::Context&, gfx::Texture&, const ImageManager&); +private: + void patchUpdatedImage(gfx::Context&, gfx::Texture&, ImagePosition& position, const ImageManager& imageManager, const std::string& name, uint16_t version); }; -ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&); +ImageAtlas makeImageAtlas(const ImageMap&, const ImageMap&, const std::unordered_map<std::string, uint32_t>& versionMap); } // namespace mbgl diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 9c9f6c6e08..d2994d6f2d 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -1,9 +1,16 @@ #include <mbgl/renderer/image_manager.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/gfx/context.hpp> +#include <mbgl/renderer/image_manager_observer.hpp> namespace mbgl { +static ImageManagerObserver nullObserver; + +void ImageManager::setObserver(ImageManagerObserver* observer_) { + observer = observer_ ? observer_ : &nullObserver; +} + void ImageManager::setLoaded(bool loaded_) { if (loaded == loaded_) { return; @@ -13,7 +20,7 @@ void ImageManager::setLoaded(bool loaded_) { if (loaded) { for (const auto& entry : requestors) { - notify(*entry.first, entry.second); + checkMissingAndNotify(*entry.first, entry.second); } requestors.clear(); } @@ -28,9 +35,23 @@ void ImageManager::addImage(Immutable<style::Image::Impl> image_) { images.emplace(image_->id, std::move(image_)); } -void ImageManager::updateImage(Immutable<style::Image::Impl> image_) { +bool ImageManager::updateImage(Immutable<style::Image::Impl> image_) { + auto oldImage = images.find(image_->id); + assert(oldImage != images.end()); + if (oldImage == images.end()) return false; + + auto sizeChanged = oldImage->second->image.size != image_->image.size; + + if (sizeChanged) { + updatedImageVersions.erase(image_->id); + } else { + updatedImageVersions[image_->id]++; + } + removeImage(image_->id); addImage(std::move(image_)); + + return sizeChanged; } void ImageManager::removeImage(const std::string& id) { @@ -60,10 +81,15 @@ const style::Image::Impl* ImageManager::getImage(const std::string& id) const { } void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) { - // If the sprite has been loaded, or if all the icon dependencies are already present - // (i.e. if they've been addeded via runtime styling), then notify the requestor immediately. - // Otherwise, delay notification until the sprite is loaded. At that point, if any of the - // dependencies are still unavailable, we'll just assume they are permanently missing. + // remove previous requests from this tile + removeRequestor(requestor); + + // If all the icon dependencies are already present ((i.e. if they've been addeded via + // runtime styling), then notify the requestor immediately. Otherwise, if the + // sprite has not loaded, then wait for it. When the sprite has loaded check + // if all icons are available. If any are missing, call `onStyleImageMissing` + // to give the user a chance to provide the icon. If they are not provided + // by the next frame we'll assume they are permanently missing. bool hasAllDependencies = true; if (!isLoaded()) { for (const auto& dependency : pair.first) { @@ -72,29 +98,83 @@ void ImageManager::getImages(ImageRequestor& requestor, ImageRequestPair&& pair) } } } - if (isLoaded() || hasAllDependencies) { - notify(requestor, std::move(pair)); - } else { + + if (hasAllDependencies) { + notify(requestor, pair); + } else if (!isLoaded()) { requestors.emplace(&requestor, std::move(pair)); + } else { + checkMissingAndNotify(requestor, std::move(pair)); } } void ImageManager::removeRequestor(ImageRequestor& requestor) { requestors.erase(&requestor); + missingImageRequestors.erase(&requestor); +} + +void ImageManager::notifyIfMissingImageAdded() { + for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { + if (it->second.callbacksRemaining == 0) { + notify(*it->first, it->second.pair); + missingImageRequestors.erase(it++); + } else { + it++; + } + } +} + +void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { + unsigned int missing = 0; + for (const auto& dependency : pair.first) { + auto it = images.find(dependency.first); + if (it == images.end()) { + missing++; + } + } + + if (missing > 0) { + ImageRequestor* requestorPtr = &requestor; + + missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { std::move(pair), missing }); + + for (const auto& dependency : pair.first) { + auto it = images.find(dependency.first); + if (it == images.end()) { + assert(observer != nullptr); + observer->onStyleImageMissing(dependency.first, [this, requestorPtr]() { + auto requestorIt = missingImageRequestors.find(requestorPtr); + if (requestorIt != missingImageRequestors.end()) { + assert(requestorIt->second.callbacksRemaining > 0); + requestorIt->second.callbacksRemaining--; + } + }); + } + } + + } else { + notify(requestor, pair); + } } void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pair) const { ImageMap iconMap; ImageMap patternMap; + ImageVersionMap versionMap; for (const auto& dependency : pair.first) { auto it = images.find(dependency.first); if (it != images.end()) { dependency.second == ImageType::Pattern ? patternMap.emplace(*it) : iconMap.emplace(*it); + + auto versionIt = updatedImageVersions.find(dependency.first); + if (versionIt != updatedImageVersions.end()) { + versionMap.emplace(versionIt->first, versionIt->second); + } } } - requestor.onImagesAvailable(iconMap, patternMap, pair.second); + requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index e56f30ac3f..99887ae384 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -6,6 +6,7 @@ #include <mbgl/util/immutable.hpp> #include <mbgl/util/optional.hpp> #include <mbgl/gfx/texture.hpp> +#include <mbgl/renderer/image_manager_observer.hpp> #include <mapbox/shelf-pack.hpp> @@ -21,7 +22,7 @@ class Context; class ImageRequestor { public: virtual ~ImageRequestor() = default; - virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, uint64_t imageCorrelationID) = 0; + virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; }; /* @@ -39,6 +40,8 @@ public: ImageManager(); ~ImageManager(); + void setObserver(ImageManagerObserver*); + void setLoaded(bool); bool isLoaded() const; @@ -47,20 +50,31 @@ public: const style::Image::Impl* getImage(const std::string&) const; void addImage(Immutable<style::Image::Impl>); - void updateImage(Immutable<style::Image::Impl>); + bool updateImage(Immutable<style::Image::Impl>); void removeImage(const std::string&); void getImages(ImageRequestor&, ImageRequestPair&&); void removeRequestor(ImageRequestor&); + void notifyIfMissingImageAdded(); + + ImageVersionMap updatedImageVersions; private: + void checkMissingAndNotify(ImageRequestor&, const ImageRequestPair&); void notify(ImageRequestor&, const ImageRequestPair&) const; bool loaded = false; - std::unordered_map<ImageRequestor*, ImageRequestPair> requestors; + std::map<ImageRequestor*, ImageRequestPair> requestors; + struct MissingImageRequestPair { + ImageRequestPair pair; + unsigned int callbacksRemaining; + }; + std::map<ImageRequestor*, MissingImageRequestPair> missingImageRequestors; ImageMap images; + ImageManagerObserver* observer = nullptr; + // Pattern stuff public: optional<ImagePosition> getPattern(const std::string& name); diff --git a/src/mbgl/renderer/image_manager_observer.hpp b/src/mbgl/renderer/image_manager_observer.hpp new file mode 100644 index 0000000000..3dc53c9b66 --- /dev/null +++ b/src/mbgl/renderer/image_manager_observer.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <mbgl/renderer/renderer_observer.hpp> + +namespace mbgl { + +class ImageManagerObserver { +public: + virtual ~ImageManagerObserver() = default; + + virtual void onStyleImageMissing(const std::string&, std::function<void()> done) { done(); } +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 32e05a38ab..269b227a7d 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -9,7 +9,6 @@ #include <mbgl/util/tile_cover.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> namespace mbgl { @@ -103,7 +102,7 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { parameters.state ), BackgroundPatternProgram::TextureBindings{ - textures::u_image::Value{ parameters.imageManager.textureBinding(parameters.context) }, + textures::image::Value{ parameters.imageManager.textureBinding(parameters.context) }, } ); } @@ -112,9 +111,9 @@ void RenderBackgroundLayer::render(PaintParameters& parameters, RenderSource*) { draw( parameters.programs.getBackgroundLayerPrograms().background, BackgroundProgram::LayoutUniformValues { - uniforms::u_matrix::Value( parameters.matrixForTile(tileID) ), - uniforms::u_color::Value( evaluated.get<BackgroundColor>() ), - uniforms::u_opacity::Value( evaluated.get<BackgroundOpacity>() ), + uniforms::matrix::Value( parameters.matrixForTile(tileID) ), + uniforms::color::Value( evaluated.get<BackgroundColor>() ), + uniforms::opacity::Value( evaluated.get<BackgroundOpacity>() ), }, BackgroundProgram::TextureBindings{} ); diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp index 60a3bf8e01..1c13a6152b 100644 --- a/src/mbgl/renderer/layers/render_circle_layer.cpp +++ b/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -8,7 +8,6 @@ #include <mbgl/style/layers/circle_layer_impl.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/intersection_tests.hpp> @@ -66,23 +65,23 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) { const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); - auto& programInstance = parameters.programs.getCircleLayerPrograms().circle.get(evaluated); + auto& programInstance = parameters.programs.getCircleLayerPrograms().circle; const auto allUniformValues = programInstance.computeAllUniformValues( CircleProgram::LayoutUniformValues { - uniforms::u_matrix::Value( + uniforms::matrix::Value( tile.translatedMatrix(evaluated.get<CircleTranslate>(), evaluated.get<CircleTranslateAnchor>(), parameters.state) ), - uniforms::u_scale_with_map::Value( scaleWithMap ), - uniforms::u_extrude_scale::Value( pitchWithMap + uniforms::scale_with_map::Value( scaleWithMap ), + uniforms::extrude_scale::Value( pitchWithMap ? std::array<float, 2> {{ tile.id.pixelsToTileUnits(1, parameters.state.getZoom()), tile.id.pixelsToTileUnits(1, parameters.state.getZoom()) }} : parameters.pixelsToGLUnits ), - uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ), - uniforms::u_pitch_with_map::Value( pitchWithMap ) + uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ), + uniforms::pitch_with_map::Value( pitchWithMap ) }, paintPropertyBinders, evaluated, diff --git a/src/mbgl/renderer/layers/render_custom_layer.cpp b/src/mbgl/renderer/layers/render_custom_layer.cpp index bcb0decb74..8ac7d29ff6 100644 --- a/src/mbgl/renderer/layers/render_custom_layer.cpp +++ b/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -57,7 +57,8 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*) MBGL_CHECK_ERROR(host->initialize()); } - gl::Context& glContext = paintParameters.context; + // TODO: remove cast + gl::Context& glContext = reinterpret_cast<gl::Context&>(paintParameters.context); const TransformState& state = paintParameters.state; // Reset GL state to a known state so the CustomLayer always has a clean slate. diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index 5af4732aa3..13ef84f169 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -51,6 +51,9 @@ bool RenderFillExtrusionLayer::hasCrossfade() const { } void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*) { + // TODO: remove cast + gl::Context& glContext = reinterpret_cast<gl::Context&>(parameters.context); + if (parameters.pass == RenderPass::Opaque) { return; } @@ -69,8 +72,8 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* // Flag the depth buffer as no longer needing to be cleared for the remainder of this pass. parameters.staticData.depthRenderbuffer->shouldClear(false); - parameters.context.setStencilMode(gfx::StencilMode::disabled()); - parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {}); + glContext.setStencilMode(gfx::StencilMode::disabled()); + glContext.clear(Color{ 0.0f, 0.0f, 0.0f, 0.0f }, depthClearValue, {}); auto draw = [&](auto& programInstance, const auto& tileBucket, auto&& uniformValues, const optional<ImagePosition>& patternPositionA, @@ -116,7 +119,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* FillExtrusionBucket& bucket = *bucket_; draw( - parameters.programs.getFillExtrusionLayerPrograms().fillExtrusion.get(evaluated), + parameters.programs.getFillExtrusionLayerPrograms().fillExtrusion, bucket, FillExtrusionProgram::layoutUniformValues( tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(), @@ -143,7 +146,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* FillExtrusionBucket& bucket = *bucket_; draw( - parameters.programs.getFillExtrusionLayerPrograms().fillExtrusionPattern.get(evaluated), + parameters.programs.getFillExtrusionLayerPrograms().fillExtrusionPattern, bucket, FillExtrusionPatternProgram::layoutUniformValues( tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(), @@ -160,7 +163,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* patternPosA, patternPosB, FillExtrusionPatternProgram::TextureBindings{ - textures::u_image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, } ); } @@ -179,9 +182,9 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* const auto allUniformValues = programInstance.computeAllUniformValues( ExtrusionTextureProgram::LayoutUniformValues{ - uniforms::u_matrix::Value( viewportMat ), - uniforms::u_world::Value( size ), - uniforms::u_opacity::Value( evaluated.get<FillExtrusionOpacity>() ) + uniforms::matrix::Value( viewportMat ), + uniforms::world::Value( size ), + uniforms::opacity::Value( evaluated.get<FillExtrusionOpacity>() ) }, paintAttributeData, properties, @@ -207,7 +210,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource* allUniformValues, allAttributeBindings, ExtrusionTextureProgram::TextureBindings{ - textures::u_image::Value{ *renderTexture->getTexture().resource }, + textures::image::Value{ *renderTexture->getTexture().resource }, }, getID()); } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 64f3448c69..205a38e380 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -63,6 +63,9 @@ bool RenderFillLayer::hasCrossfade() const { } void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { + // TODO: remove cast + gl::Context& glContext = reinterpret_cast<gl::Context&>(parameters.context); + if (unevaluated.get<FillPattern>().isUndefined()) { for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<FillBucket>(*baseImpl); @@ -71,24 +74,22 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { } FillBucket& bucket = *bucket_; - auto draw = [&] (auto& program, + auto draw = [&] (auto& programInstance, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments, auto&& textureBindings) { - auto& programInstance = program.get(evaluated); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); const auto allUniformValues = programInstance.computeAllUniformValues( FillProgram::LayoutUniformValues { - uniforms::u_matrix::Value( + uniforms::matrix::Value( tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state) ), - uniforms::u_world::Value( parameters.context.viewport.getCurrentValue().size ), + uniforms::world::Value( glContext.viewport.getCurrentValue().size ), }, paintPropertyBinders, evaluated, @@ -159,14 +160,12 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { } FillBucket& bucket = *bucket_; - auto draw = [&] (auto& program, + auto draw = [&] (auto& programInstance, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments, auto&& textureBindings) { - auto& programInstance = program.get(evaluated); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); @@ -175,7 +174,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state), - parameters.context.viewport.getCurrentValue().size, + glContext.viewport.getCurrentValue().size, geometryTile.iconAtlasTexture->size, crossfade, tile.id, @@ -216,7 +215,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { *bucket.triangleIndexBuffer, bucket.triangleSegments, FillPatternProgram::TextureBindings{ - textures::u_image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, }); if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) { @@ -226,7 +225,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { *bucket.lineIndexBuffer, bucket.lineSegments, FillOutlinePatternProgram::TextureBindings{ - textures::u_image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, }); } } diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index efc16fb28a..f8ba68965e 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -52,12 +52,15 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { return; } + // TODO: remove cast + gl::Context& glContext = reinterpret_cast<gl::Context&>(parameters.context); + if (parameters.pass == RenderPass::Pass3D) { const auto& viewportSize = parameters.staticData.backendSize; const auto size = Size{viewportSize.width / 4, viewportSize.height / 4}; if (!renderTexture || renderTexture->getSize() != size) { - if (parameters.context.supportsHalfFloatTextures) { + if (glContext.supportsHalfFloatTextures) { renderTexture = OffscreenTexture(parameters.context, size, gfx::TextureChannelDataType::HalfFloat); try { @@ -65,11 +68,11 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { } catch (const std::runtime_error& ex) { // can't render to a half-float texture; falling back to unsigned byte one renderTexture = nullopt; - parameters.context.supportsHalfFloatTextures = false; + glContext.supportsHalfFloatTextures = false; } } - if (!parameters.context.supportsHalfFloatTextures || !renderTexture) { + if (!glContext.supportsHalfFloatTextures || !renderTexture) { renderTexture = OffscreenTexture(parameters.context, size, gfx::TextureChannelDataType::UnsignedByte); renderTexture->bind(); } @@ -82,7 +85,7 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { colorRampTexture = parameters.context.createTexture(colorRamp, gfx::TextureChannelDataType::UnsignedByte); } - parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); + glContext.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<HeatmapBucket>(*baseImpl); @@ -99,13 +102,13 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); - auto& programInstance = parameters.programs.getHeatmapLayerPrograms().heatmap.get(evaluated); + auto& programInstance = parameters.programs.getHeatmapLayerPrograms().heatmap; const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapProgram::LayoutUniformValues { - uniforms::u_intensity::Value( evaluated.get<style::HeatmapIntensity>() ), - uniforms::u_matrix::Value( tile.matrix ), - uniforms::heatmap::u_extrude_scale::Value( extrudeScale ) + uniforms::intensity::Value( evaluated.get<style::HeatmapIntensity>() ), + uniforms::matrix::Value( tile.matrix ), + uniforms::heatmap::extrude_scale::Value( extrudeScale ) }, paintPropertyBinders, evaluated, @@ -148,9 +151,9 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapTextureProgram::LayoutUniformValues{ - uniforms::u_matrix::Value( viewportMat ), - uniforms::u_world::Value( size ), - uniforms::u_opacity::Value( evaluated.get<HeatmapOpacity>() ) + uniforms::matrix::Value( viewportMat ), + uniforms::world::Value( size ), + uniforms::opacity::Value( evaluated.get<HeatmapOpacity>() ) }, paintAttributeData, properties, @@ -176,8 +179,8 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { allUniformValues, allAttributeBindings, HeatmapTextureProgram::TextureBindings{ - textures::u_image::Value{ *renderTexture->getTexture().resource, gfx::TextureFilterType::Linear }, - textures::u_color_ramp::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *renderTexture->getTexture().resource, gfx::TextureFilterType::Linear }, + textures::color_ramp::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear }, }, getID() ); diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 00ecad444c..1d030f5946 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -10,7 +10,6 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/style/layers/hillshade_layer_impl.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/util/geo.hpp> #include <mbgl/util/offscreen_texture.hpp> @@ -77,12 +76,12 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src const auto allUniformValues = programInstance.computeAllUniformValues( HillshadeProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_highlight::Value( evaluated.get<HillshadeHighlightColor>() ), - uniforms::u_shadow::Value( evaluated.get<HillshadeShadowColor>() ), - uniforms::u_accent::Value( evaluated.get<HillshadeAccentColor>() ), - uniforms::u_light::Value( getLight(parameters) ), - uniforms::u_latrange::Value( getLatRange(id) ), + uniforms::matrix::Value( matrix ), + uniforms::highlight::Value( evaluated.get<HillshadeHighlightColor>() ), + uniforms::shadow::Value( evaluated.get<HillshadeShadowColor>() ), + uniforms::accent::Value( evaluated.get<HillshadeAccentColor>() ), + uniforms::light::Value( getLight(parameters) ), + uniforms::latrange::Value( getLatRange(id) ), }, paintAttributeData, evaluated, @@ -141,10 +140,10 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src const auto allUniformValues = programInstance.computeAllUniformValues( HillshadePrepareProgram::LayoutUniformValues { - uniforms::u_matrix::Value( mat ), - uniforms::u_dimension::Value( {{stride, stride}} ), - uniforms::u_zoom::Value( float(tile.id.canonical.z) ), - uniforms::u_maxzoom::Value( float(maxzoom) ), + uniforms::matrix::Value( mat ), + uniforms::dimension::Value( {{stride, stride}} ), + uniforms::zoom::Value( float(tile.id.canonical.z) ), + uniforms::maxzoom::Value( float(maxzoom) ), }, paintAttributeData, properties, @@ -170,7 +169,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src allUniformValues, allAttributeBindings, HillshadePrepareProgram::TextureBindings{ - textures::u_image::Value{ *bucket.dem->resource }, + textures::image::Value{ *bucket.dem->resource }, }, getID() ); @@ -187,7 +186,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src bucket.segments, tile.id, HillshadeProgram::TextureBindings{ - textures::u_image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear }, }); } else { // Draw the full tile. @@ -197,7 +196,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src parameters.staticData.rasterSegments, tile.id, HillshadeProgram::TextureBindings{ - textures::u_image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear }, }); } } diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index eee151ccaa..2d246df7f4 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -9,7 +9,6 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/style/layers/line_layer_impl.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/util/math.hpp> #include <mbgl/util/intersection_tests.hpp> @@ -34,10 +33,7 @@ void RenderLineLayer::transition(const TransitionParameters& parameters) { } void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { - style::Properties<LineFloorwidth>::Unevaluated extra(unevaluated.get<style::LineWidth>()); - evaluated = RenderLinePaintProperties::PossiblyEvaluated( - unevaluated.evaluate(parameters).concat(extra.evaluate(parameters))); - + evaluated = unevaluated.evaluate(parameters); crossfade = parameters.getCrossfadeParameters(); passes = (evaluated.get<style::LineOpacity>().constantOr(1.0) > 0 @@ -66,11 +62,10 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { } LineBucket& bucket = *bucket_; - auto draw = [&](auto& program, auto&& uniformValues, + auto draw = [&](auto& programInstance, + auto&& uniformValues, const optional<ImagePosition>& patternPositionA, const optional<ImagePosition>& patternPositionB, auto&& textureBindings) { - auto& programInstance = program.get(evaluated); - const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); paintPropertyBinders.setPatternParameters(patternPositionA, patternPositionB, crossfade); @@ -145,10 +140,10 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { texsize, crossfade, parameters.pixelRatio), - *posA, - *posB, + posA, + posB, LinePatternProgram::TextureBindings{ - textures::u_image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear }, }); } else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) { if (!colorRampTexture) { @@ -164,7 +159,7 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) { {}, {}, LineGradientProgram::TextureBindings{ - textures::u_image::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear }, + textures::image::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear }, }); } else { draw(parameters.programs.getLineLayerPrograms().line, diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 186b740234..cb4492ebc3 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -10,15 +10,6 @@ namespace mbgl { -struct LineFloorwidth : style::DataDrivenPaintProperty<float, attributes::a_floorwidth, uniforms::u_floorwidth> { - using EvaluatorType = DataDrivenPropertyEvaluator<float, true>; - static float defaultValue() { return 1.0; } -}; - -class RenderLinePaintProperties : public style::ConcatenateProperties< - style::LinePaintProperties, - style::Properties<LineFloorwidth>> {}; - class RenderLineLayer: public RenderLayer { public: using StyleLayerImpl = style::LineLayer::Impl; @@ -44,7 +35,7 @@ public: // Paint properties style::LinePaintProperties::Unevaluated unevaluated; - RenderLinePaintProperties::PossiblyEvaluated evaluated; + style::LinePaintProperties::PossiblyEvaluated evaluated; const style::LineLayer::Impl& impl() const; diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index c8f00eb1fd..94c4a8dc42 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -8,7 +8,6 @@ #include <mbgl/programs/raster_program.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/style/layers/raster_layer_impl.hpp> namespace mbgl { @@ -85,17 +84,17 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source const auto allUniformValues = programInstance.computeAllUniformValues( RasterProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_opacity::Value( evaluated.get<RasterOpacity>() ), - uniforms::u_fade_t::Value( 1 ), - uniforms::u_brightness_low::Value( evaluated.get<RasterBrightnessMin>() ), - uniforms::u_brightness_high::Value( evaluated.get<RasterBrightnessMax>() ), - uniforms::u_saturation_factor::Value( saturationFactor(evaluated.get<RasterSaturation>()) ), - uniforms::u_contrast_factor::Value( contrastFactor(evaluated.get<RasterContrast>()) ), - uniforms::u_spin_weights::Value( spinWeights(evaluated.get<RasterHueRotate>()) ), - uniforms::u_buffer_scale::Value( 1.0f ), - uniforms::u_scale_parent::Value( 1.0f ), - uniforms::u_tl_parent::Value( std::array<float, 2> {{ 0.0f, 0.0f }} ), + uniforms::matrix::Value( matrix ), + uniforms::opacity::Value( evaluated.get<RasterOpacity>() ), + uniforms::fade_t::Value( 1 ), + uniforms::brightness_low::Value( evaluated.get<RasterBrightnessMin>() ), + uniforms::brightness_high::Value( evaluated.get<RasterBrightnessMax>() ), + uniforms::saturation_factor::Value( saturationFactor(evaluated.get<RasterSaturation>()) ), + uniforms::contrast_factor::Value( contrastFactor(evaluated.get<RasterContrast>()) ), + uniforms::spin_weights::Value( spinWeights(evaluated.get<RasterHueRotate>()) ), + uniforms::buffer_scale::Value( 1.0f ), + uniforms::scale_parent::Value( 1.0f ), + uniforms::tl_parent::Value( std::array<float, 2> {{ 0.0f, 0.0f }} ), }, paintAttributeData, evaluated, @@ -138,8 +137,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ - textures::u_image0::Value{ *bucket.texture->resource, filter }, - textures::u_image1::Value{ *bucket.texture->resource, filter }, + textures::image0::Value{ *bucket.texture->resource, filter }, + textures::image1::Value{ *bucket.texture->resource, filter }, }); } } @@ -162,8 +161,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ - textures::u_image0::Value{ *bucket.texture->resource, filter }, - textures::u_image1::Value{ *bucket.texture->resource, filter }, + textures::image0::Value{ *bucket.texture->resource, filter }, + textures::image1::Value{ *bucket.texture->resource, filter }, }); } else { // Draw the full tile. @@ -172,8 +171,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.rasterSegments, RasterProgram::TextureBindings{ - textures::u_image0::Value{ *bucket.texture->resource, filter }, - textures::u_image1::Value{ *bucket.texture->resource, filter }, + textures::image0::Value{ *bucket.texture->resource, filter }, + textures::image1::Value{ *bucket.texture->resource, filter }, }); } } diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 31d92dd414..d7951c647a 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -5,6 +5,7 @@ #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/text/shaping.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/programs/symbol_program.hpp> #include <mbgl/programs/collision_box_program.hpp> @@ -13,8 +14,8 @@ #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/layout/symbol_projection.hpp> +#include <mbgl/layout/symbol_layout.hpp> #include <mbgl/util/math.hpp> #include <cmath> @@ -23,6 +24,19 @@ namespace mbgl { using namespace style; +namespace { +Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) { + AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); + float shiftX = -(alignment.horizontalAlign - 0.5f) * width; + float shiftY = -(alignment.verticalAlign - 0.5f) * height; + Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset); + return Point<float>( + (shiftX / textBoxScale + offset.x) * renderTextSize, + (shiftY / textBoxScale + offset.y) * renderTextSize + ); +} +} // namespace + RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl) : RenderLayer(std::move(_impl)), unevaluated(impl().paint.untransitioned()) { @@ -89,17 +103,14 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { const auto& evaluated_ = bucketPaintProperties.evaluated; const auto& layout = bucket.layout; - auto draw = [&] (auto& program, + auto draw = [&] (auto& programInstance, auto&& uniformValues, const auto& buffers, const auto& symbolSizeBinder, const SymbolPropertyValues& values_, const auto& binders, const auto& paintProperties, - auto&& textureBindings) - { - auto& programInstance = program.get(paintProperties); - + auto&& textureBindings) { const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), *symbolSizeBinder, @@ -172,7 +183,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, @@ -185,7 +196,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, @@ -197,7 +208,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { } } else { draw(parameters.programs.getSymbolLayerPrograms().symbolIcon, - SymbolIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), + SymbolIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), bucket.icon, bucket.iconSizeBinder, values, @@ -215,6 +226,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { auto values = textPropertyValues(evaluated_, layout); const auto& paintPropertyValues = textPaintProperties(evaluated_); + bool hasVariablePacement = false; const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point && layout.get<TextRotationAlignment>() == AlignmentType::Map; @@ -229,13 +241,79 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.state); parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); + } else if (!layout.get<TextVariableAnchor>().empty()) { + bucket.text.dynamicVertices.clear(); + + const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(parameters.state.getZoom()); + const float tileScale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); + const bool rotateWithMap = layout.get<TextRotationAlignment>() == AlignmentType::Map; + const bool pitchWithMap = layout.get<TextPitchAlignment>() == AlignmentType::Map; + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, parameters.state.getZoom()); + const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, parameters.state, pixelsToTileUnits); + + for (const PlacedSymbol& symbol : bucket.text.placedSymbols) { + optional<VariableOffset> variableOffset; + if (!symbol.hidden && symbol.crossTileID != 0u) { + auto it = parameters.variableOffsets.get().find(symbol.crossTileID); + if (it != parameters.variableOffsets.get().end()) { + variableOffset = it->second; + hasVariablePacement |= true; + } + } + + if (!variableOffset) { + // These symbols are from a justification that is not being used, or a label that wasn't placed + // so we don't need to do the extra math to figure out what incremental shift to apply. + hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices); + } else { + const Point<float> tileAnchor = symbol.anchorPoint; + const auto projectedAnchor = project(tileAnchor, pitchWithMap ? tile.matrix : labelPlaneMatrix); + const float perspectiveRatio = 0.5f + 0.5f * (parameters.state.getCameraToCenterDistance() / projectedAnchor.second); + float renderTextSize = evaluateSizeForFeature(partiallyEvaluatedSize, symbol) * perspectiveRatio / util::ONE_EM; + if (pitchWithMap) { + // Go from size in pixels to equivalent size in tile units + renderTextSize *= bucket.tilePixelRatio / tileScale; + } + + auto shift = calculateVariableRenderShift( + (*variableOffset).anchor, + (*variableOffset).width, + (*variableOffset).height, + (*variableOffset).radialOffset, + (*variableOffset).textBoxScale, + renderTextSize); + + // Usual case is that we take the projected anchor and add the pixel-based shift + // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent + // tile-unit based shift to the anchor before projecting to the label plane. + Point<float> shiftedAnchor; + if (pitchWithMap) { + shiftedAnchor = project(Point<float>(tileAnchor.x + shift.x, tileAnchor.y + shift.y), + labelPlaneMatrix).first; + } else { + if (rotateWithMap) { + auto rotated = util::rotate(shift, -parameters.state.getPitch()); + shiftedAnchor = Point<float>(projectedAnchor.first.x + rotated.x, + projectedAnchor.first.y + rotated.y); + } else { + shiftedAnchor = Point<float>(projectedAnchor.first.x + shift.x, + projectedAnchor.first.y + shift.y); + } + } + + for (std::size_t i = 0; i < symbol.glyphOffsets.size(); i++) { + addDynamicAttributes(shiftedAnchor, 0, bucket.text.dynamicVertices); + } + } + } + parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); } const Size texsize = geometryTile.glyphAtlasTexture->size; if (values.hasHalo) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, @@ -248,7 +326,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, @@ -280,9 +358,9 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), CollisionBoxProgram::LayoutUniformValues { - uniforms::u_matrix::Value( tile.matrix ), - uniforms::u_extrude_scale::Value( extrudeScale ), - uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) + uniforms::matrix::Value( tile.matrix ), + uniforms::extrude_scale::Value( extrudeScale ), + uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.dynamicVertexBuffer, @@ -316,10 +394,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), CollisionCircleProgram::LayoutUniformValues { - uniforms::u_matrix::Value( tile.matrix ), - uniforms::u_extrude_scale::Value( extrudeScale ), - uniforms::u_overscale_factor::Value( float(tile.tile.id.overscaleFactor()) ), - uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) + uniforms::matrix::Value( tile.matrix ), + uniforms::extrude_scale::Value( extrudeScale ), + uniforms::overscale_factor::Value( float(tile.tile.id.overscaleFactor()) ), + uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionCircle.vertexBuffer, *bucket.collisionCircle.dynamicVertexBuffer, @@ -392,12 +470,9 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S }; } -RenderLayer::RenderTiles RenderSymbolLayer::filterRenderTiles(RenderTiles tiles) const { +void RenderSymbolLayer::setRenderTiles(RenderTiles tiles, const TransformState& state) { auto filterFn = [](auto& tile){ return !tile.tile.isRenderable(); }; - return RenderLayer::filterRenderTiles(std::move(tiles), filterFn); -} - -void RenderSymbolLayer::sortRenderTiles(const TransformState& state) { + renderTiles = RenderLayer::filterRenderTiles(std::move(tiles), filterFn); // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn // on top of each other, with lower symbols being drawn on top of higher symbols. std::sort(renderTiles.begin(), renderTiles.end(), [&state](const auto& a, const auto& b) { diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index e44ad398f4..4de5c8538a 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -57,7 +57,7 @@ class BucketParameters; class SymbolLayout; class GeometryTileLayer; -class RenderSymbolLayer: public RenderLayer, public RenderLayerSymbolInterface { +class RenderSymbolLayer final: public RenderLayer, public RenderLayerSymbolInterface { public: RenderSymbolLayer(Immutable<style::SymbolLayer::Impl>); ~RenderSymbolLayer() final = default; @@ -67,6 +67,7 @@ public: bool hasTransition() const override; bool hasCrossfade() const override; void render(PaintParameters&, RenderSource*) override; + void setRenderTiles(RenderTiles, const TransformState&) override; static style::IconPaintProperties::PossiblyEvaluated iconPaintProperties(const style::SymbolPaintProperties::PossiblyEvaluated&); static style::TextPaintProperties::PossiblyEvaluated textPaintProperties(const style::SymbolPaintProperties::PossiblyEvaluated&); @@ -91,8 +92,6 @@ protected: const style::SymbolLayoutProperties::PossiblyEvaluated&); static style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated&, const style::SymbolLayoutProperties::PossiblyEvaluated&); - RenderTiles filterRenderTiles(RenderTiles) const final; - void sortRenderTiles(const TransformState&) final; void updateBucketPaintProperties(Bucket*) const final; }; diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index 2237b016d2..55dbf70472 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -5,7 +5,7 @@ namespace mbgl { -PaintParameters::PaintParameters(gl::Context& context_, +PaintParameters::PaintParameters(gfx::Context& context_, float pixelRatio_, GLContextMode contextMode_, RendererBackend& backend_, @@ -13,7 +13,8 @@ PaintParameters::PaintParameters(gl::Context& context_, const EvaluatedLight& evaluatedLight_, RenderStaticData& staticData_, ImageManager& imageManager_, - LineAtlas& lineAtlas_) + LineAtlas& lineAtlas_, + Placement::VariableOffsets variableOffsets_) : context(context_), backend(backend_), state(updateParameters.transformState), @@ -26,6 +27,7 @@ PaintParameters::PaintParameters(gl::Context& context_, contextMode(contextMode_), timePoint(updateParameters.timePoint), pixelRatio(pixelRatio_), + variableOffsets(variableOffsets_), #ifndef NDEBUG programs((debugOptions & MapDebugOptions::Overdraw) ? staticData_.overdrawPrograms : staticData_.programs) #else diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index ea3b41adfe..537158a68e 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -9,6 +9,7 @@ #include <mbgl/gfx/color_mode.hpp> #include <mbgl/util/mat4.hpp> #include <mbgl/algorithm/generate_clip_ids.hpp> +#include <mbgl/text/placement.hpp> #include <array> @@ -23,13 +24,13 @@ class ImageManager; class LineAtlas; class UnwrappedTileID; -namespace gl { +namespace gfx { class Context; -} // namespace gl +} // namespace gfx class PaintParameters { public: - PaintParameters(gl::Context&, + PaintParameters(gfx::Context&, float pixelRatio, GLContextMode, RendererBackend&, @@ -37,9 +38,10 @@ public: const EvaluatedLight&, RenderStaticData&, ImageManager&, - LineAtlas&); + LineAtlas&, + Placement::VariableOffsets); - gl::Context& context; + gfx::Context& context; RendererBackend& backend; const TransformState& state; @@ -56,6 +58,7 @@ public: TimePoint timePoint; float pixelRatio; + Placement::VariableOffsets variableOffsets; std::array<float, 2> pixelsToGLUnits; algorithm::ClipIDGenerator clipIDGenerator; diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index a014b36ece..dd56afb2e8 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -4,6 +4,7 @@ #include <mbgl/gfx/uniform.hpp> #include <mbgl/gfx/attribute.hpp> #include <mbgl/programs/attributes.hpp> +#include <mbgl/util/literal.hpp> #include <mbgl/util/type_list.hpp> #include <mbgl/renderer/possibly_evaluated_property_value.hpp> #include <mbgl/renderer/paint_property_statistics.hpp> @@ -147,7 +148,7 @@ public: void upload(gfx::Context&) override {} void setPatternParameters(const optional<ImagePosition>& posA, const optional<ImagePosition>& posB, CrossfadeParameters&) override { - if (!posA && !posB) { + if (!posA || !posB) { return; } else { constantPatternPositions = std::tuple<std::array<uint16_t, 4>, std::array<uint16_t, 4>> { posB->tlbr(), posA->tlbr() }; @@ -431,17 +432,15 @@ PaintPropertyBinder<T, UniformValueType, PossiblyEvaluatedType, As...>::create(c } template <class Attr> -struct ZoomInterpolatedAttribute { - static auto name() { return Attr::name(); } +struct ZoomInterpolatedAttribute : public Attr { using Type = ZoomInterpolatedAttributeType<typename Attr::Type>; }; template <class Attr> struct InterpolationUniform { using Value = float; - static auto name() { - static const std::string name = Attr::name() + std::string("_t"); - return name.c_str(); + static constexpr auto name() { + return concat_literals<&Attr::name, &string_literal<'_', 't'>::value>::value(); } }; @@ -546,29 +545,6 @@ public: return result; } - template <class> - struct UniformDefines; - - template <class... Us> - struct UniformDefines<TypeList<Us...>> { - static void appendDefines(std::vector<std::string>& defines) { - util::ignore({ - (defines.push_back(std::string("#define HAS_UNIFORM_") + Us::name()), 0)... - }); - } - }; - - template <class EvaluatedProperties> - static std::vector<std::string> defines(const EvaluatedProperties& currentProperties) { - std::vector<std::string> result; - util::ignore({ - (currentProperties.template get<Ps>().isConstant() - ? UniformDefines<typename Ps::UniformList>::appendDefines(result) - : (void) 0, 0)... - }); - return result; - } - private: Binders binders; }; diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index 32236d0f24..24a45b9146 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -3,7 +3,7 @@ #include <mbgl/renderer/render_tile.hpp> #include <mbgl/style/types.hpp> #include <mbgl/tile/tile.hpp> -#include <mbgl/gl/context.hpp> +#include <mbgl/gfx/context.hpp> #include <mbgl/util/logging.hpp> namespace mbgl { @@ -33,18 +33,9 @@ bool RenderLayer::needsRendering(float zoom) const { && baseImpl->maxZoom >= zoom; } -void RenderLayer::setRenderTiles(RenderTiles tiles, const TransformState& state) { - renderTiles = filterRenderTiles(std::move(tiles)); - sortRenderTiles(state); -} - -RenderLayer::RenderTiles RenderLayer::filterRenderTiles(RenderTiles tiles) const { +void RenderLayer::setRenderTiles(RenderTiles tiles, const TransformState&) { auto filterFn = [](auto& tile){ return !tile.tile.isRenderable() || tile.tile.holdForFade(); }; - return filterRenderTiles(std::move(tiles), filterFn); -} - -void RenderLayer::sortRenderTiles(const TransformState&) { - // no-op + renderTiles = filterRenderTiles(std::move(tiles), filterFn); } const RenderLayerSymbolInterface* RenderLayer::getSymbolInterface() const { diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp index ec4c71b08c..98e151435a 100644 --- a/src/mbgl/renderer/render_layer.hpp +++ b/src/mbgl/renderer/render_layer.hpp @@ -63,7 +63,7 @@ public: const mat4&) const { return false; }; using RenderTiles = std::vector<std::reference_wrapper<RenderTile>>; - void setRenderTiles(RenderTiles, const TransformState&); + virtual void setRenderTiles(RenderTiles, const TransformState&); // Private implementation Immutable<style::Layer::Impl> baseImpl; @@ -84,9 +84,6 @@ protected: // in the console to inform the developer. void checkRenderability(const PaintParameters&, uint32_t activeBindingCount); - // Code specific to RenderTiles sorting / filtering - virtual RenderTiles filterRenderTiles(RenderTiles) const; - virtual void sortRenderTiles(const TransformState&); // For some layers, we want Buckets to cache their corresponding paint properties, so that outdated buckets (and // the cached paint properties) can be still in use while the tile is loading new buckets (which will // correpond to the current paint properties of the layer). diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index 16d0d64a33..24eed0326c 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -1,5 +1,5 @@ #include <mbgl/renderer/render_static_data.hpp> -#include <mbgl/gl/context.hpp> +#include <mbgl/gfx/context.hpp> #include <mbgl/programs/program_parameters.hpp> namespace mbgl { @@ -48,7 +48,7 @@ static gfx::VertexVector<ExtrusionTextureLayoutVertex> extrusionTextureVertices( return result; } -RenderStaticData::RenderStaticData(gl::Context& context, float pixelRatio, const optional<std::string>& programCacheDir) +RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio, const optional<std::string>& programCacheDir) : tileVertexBuffer(context.createVertexBuffer(tileVertices())), rasterVertexBuffer(context.createVertexBuffer(rasterVertices())), extrusionTextureVertexBuffer(context.createVertexBuffer(extrusionTextureVertices())), diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp index b9b52b09ca..23f632bc12 100644 --- a/src/mbgl/renderer/render_static_data.hpp +++ b/src/mbgl/renderer/render_static_data.hpp @@ -12,10 +12,13 @@ #include <string> namespace mbgl { +namespace gfx { +class Context; +} // namespace gfx class RenderStaticData { public: - RenderStaticData(gl::Context&, float pixelRatio, const optional<std::string>& programCacheDir); + RenderStaticData(gfx::Context&, float pixelRatio, const optional<std::string>& programCacheDir); gfx::VertexBuffer<gfx::Vertex<PositionOnlyLayoutAttributes>> tileVertexBuffer; gfx::VertexBuffer<RasterLayoutVertex> rasterVertexBuffer; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index 24826bfd78..745a577683 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -4,7 +4,7 @@ #include <mbgl/renderer/render_static_data.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/map/transform_state.hpp> -#include <mbgl/gl/context.hpp> +#include <mbgl/gfx/cull_face_mode.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/util/math.hpp> @@ -105,8 +105,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_color::Value( Color::white() ) + uniforms::matrix::Value( matrix ), + uniforms::color::Value( Color::white() ) }, paintAttributeData, properties, @@ -128,8 +128,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_color::Value( Color::black() ) + uniforms::matrix::Value( matrix ), + uniforms::color::Value( Color::black() ) }, paintAttributeData, properties, @@ -153,8 +153,8 @@ void RenderTile::finishRender(PaintParameters& parameters) { parameters.staticData.tileBorderSegments, program.computeAllUniformValues( DebugProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_color::Value( Color::red() ) + uniforms::matrix::Value( matrix ), + uniforms::color::Value( Color::red() ) }, paintAttributeData, properties, diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp index fbd9049207..4da7b78374 100644 --- a/src/mbgl/renderer/renderer.cpp +++ b/src/mbgl/renderer/renderer.cpp @@ -34,6 +34,10 @@ void Renderer::render(const UpdateParameters& updateParameters) { impl->render(updateParameters); } +void Renderer::flush() { + impl->flush(); +} + std::vector<Feature> Renderer::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { return impl->queryRenderedFeatures(geometry, options); } diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 471536cf40..7144a2dcee 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -16,6 +16,7 @@ #include <mbgl/renderer/query.hpp> #include <mbgl/renderer/backend_scope.hpp> #include <mbgl/renderer/image_manager.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/gl/debugging.hpp> #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/style/source_impl.hpp> @@ -82,6 +83,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { if (!imageManager) { imageManager = std::make_unique<ImageManager>(); + imageManager->setObserver(this); } if (updateParameters.mode != MapMode::Continuous) { @@ -142,6 +144,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { const ImageDifference imageDiff = diffImages(imageImpls, updateParameters.images); imageImpls = updateParameters.images; + // Only trigger tile reparse for changed images. Changed images only need a relayout when they have a different size. + bool hasImageDiff = !imageDiff.removed.empty(); + // Remove removed images from sprite atlas. for (const auto& entry : imageDiff.removed) { imageManager->removeImage(entry.first); @@ -154,9 +159,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { // Update changed images. for (const auto& entry : imageDiff.changed) { - imageManager->updateImage(entry.second.after); + hasImageDiff = imageManager->updateImage(entry.second.after) || hasImageDiff; } + imageManager->notifyIfMissingImageAdded(); imageManager->setLoaded(updateParameters.spriteLoaded); @@ -214,8 +220,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { renderSources.emplace(entry.first, std::move(renderSource)); } - const bool hasImageDiff = !(imageDiff.added.empty() && imageDiff.removed.empty() && imageDiff.changed.empty()); - // Update all sources. for (const auto& source : *sourceImpls) { std::vector<Immutable<Layer::Impl>> filteredLayers; @@ -262,7 +266,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { renderLight.getEvaluated(), *staticData, *imageManager, - *lineAtlas + *lineAtlas, + placement->getVariableOffsets() }; bool loaded = updateParameters.styleLoaded && isLoaded(); @@ -278,8 +283,11 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { backend.updateAssumedState(); + // TODO: remove cast + gl::Context& glContext = reinterpret_cast<gl::Context&>(parameters.context); + if (parameters.contextMode == GLContextMode::Shared) { - parameters.context.setDirtyState(); + glContext.setDirtyState(); } Color backgroundColor; @@ -292,6 +300,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { }; std::vector<RenderItem> order; + std::vector<const RenderLayerSymbolInterface*> renderItemsWithSymbols; for (auto& layerImpl : *layerImpls) { RenderLayer* layer = getRenderLayer(layerImpl->id); @@ -326,6 +335,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { layer->setRenderTiles(source->getRenderTiles(), parameters.state); order.emplace_back(*layer, source); + + if (const RenderLayerSymbolInterface* symbolLayer = layer->getSymbolInterface()) { + renderItemsWithSymbols.push_back(symbolLayer); + } } { @@ -334,32 +347,28 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { crossTileSymbolIndex.reset(); } - std::vector<RenderItem> renderItemsWithSymbols; - std::copy_if(order.rbegin(), order.rend(), std::back_inserter(renderItemsWithSymbols), - [](const auto& item) { return item.layer.getSymbolInterface() != nullptr; }); - bool symbolBucketsChanged = false; const bool placementChanged = !placement->stillRecent(parameters.timePoint); - std::unique_ptr<Placement> newPlacement; std::set<std::string> usedSymbolLayers; if (placementChanged) { - newPlacement = std::make_unique<Placement>(parameters.state, parameters.mapMode, updateParameters.transitionOptions, updateParameters.crossSourceCollisions); + placement = std::make_unique<Placement>(parameters.state, parameters.mapMode, updateParameters.transitionOptions, updateParameters.crossSourceCollisions, std::move(placement)); } - for (const auto& item : renderItemsWithSymbols) { - if (crossTileSymbolIndex.addLayer(*item.layer.getSymbolInterface(), parameters.state.getLatLng().longitude())) symbolBucketsChanged = true; + for (auto it = renderItemsWithSymbols.rbegin(); it != renderItemsWithSymbols.rend(); ++it) { + const RenderLayerSymbolInterface *symbolLayer = *it; + if (crossTileSymbolIndex.addLayer(*symbolLayer, parameters.state.getLatLng().longitude())) symbolBucketsChanged = true; - if (newPlacement) { - usedSymbolLayers.insert(item.layer.getID()); - newPlacement->placeLayer(*item.layer.getSymbolInterface(), parameters.projMatrix, parameters.debugOptions & MapDebugOptions::Collision); + if (placementChanged) { + usedSymbolLayers.insert(symbolLayer->layerID()); + placement->placeLayer(*symbolLayer, parameters.projMatrix, parameters.debugOptions & MapDebugOptions::Collision); } } - if (newPlacement) { - newPlacement->commit(*placement, parameters.timePoint); + if (placementChanged) { + placement->commit(parameters.timePoint); crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers); - placement = std::move(newPlacement); + parameters.variableOffsets = placement->getVariableOffsets(); updateFadingTiles(); } else { placement->setStale(); @@ -368,8 +377,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { parameters.symbolFadeChange = placement->symbolFadeChange(parameters.timePoint); if (placementChanged || symbolBucketsChanged) { - for (const auto& item : renderItemsWithSymbols) { - placement->updateLayerOpacities(*item.layer.getSymbolInterface()); + for (auto it = renderItemsWithSymbols.rbegin(); it != renderItemsWithSymbols.rend(); ++it) { + const RenderLayerSymbolInterface *symbolLayer = *it; + placement->updateLayerOpacities(*symbolLayer); } } } @@ -402,7 +412,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { if (!parameters.staticData.depthRenderbuffer || parameters.staticData.depthRenderbuffer->size != parameters.staticData.backendSize) { parameters.staticData.depthRenderbuffer = - parameters.context.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize); + glContext.createRenderbuffer<gl::RenderbufferType::DepthComponent>(parameters.staticData.backendSize); } parameters.staticData.depthRenderbuffer->shouldClear(true); @@ -425,11 +435,11 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { MBGL_DEBUG_GROUP(parameters.context, "clear"); parameters.backend.bind(); if (parameters.debugOptions & MapDebugOptions::Overdraw) { - parameters.context.clear(Color::black(), ClearDepth::Default, ClearStencil::Default); + glContext.clear(Color::black(), ClearDepth::Default, ClearStencil::Default); } else if (parameters.contextMode == GLContextMode::Shared) { - parameters.context.clear({}, ClearDepth::Default, ClearStencil::Default); + glContext.clear({}, ClearDepth::Default, ClearStencil::Default); } else { - parameters.context.clear(backgroundColor, ClearDepth::Default, ClearStencil::Default); + glContext.clear(backgroundColor, ClearDepth::Default, ClearStencil::Default); } } @@ -462,7 +472,7 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { parameters.staticData.tileTriangleSegments, program.computeAllUniformValues( ClippingMaskProgram::LayoutUniformValues { - uniforms::u_matrix::Value( parameters.matrixForTile(clipID.first) ), + uniforms::matrix::Value( parameters.matrixForTile(clipID.first) ), }, paintAttributeData, properties, @@ -482,17 +492,17 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { #if not MBGL_USE_GLES2 and not defined(NDEBUG) // Render tile clip boundaries, using stencil buffer to calculate fill color. if (parameters.debugOptions & MapDebugOptions::StencilClip) { - parameters.context.setStencilMode(gfx::StencilMode::disabled()); - parameters.context.setDepthMode(gfx::DepthMode::disabled()); - parameters.context.setColorMode(gfx::ColorMode::unblended()); - parameters.context.program = 0; + glContext.setStencilMode(gfx::StencilMode::disabled()); + glContext.setDepthMode(gfx::DepthMode::disabled()); + glContext.setColorMode(gfx::ColorMode::unblended()); + glContext.program = 0; // Reset the value in case someone else changed it, or it's dirty. - parameters.context.pixelTransferStencil = gl::value::PixelTransferStencil::Default; + glContext.pixelTransferStencil = gl::value::PixelTransferStencil::Default; // Read the stencil buffer - const auto viewport = parameters.context.viewport.getCurrentValue(); - auto image = parameters.context.readFramebuffer<AlphaImage, gfx::TexturePixelType::Stencil>(viewport.size, false); + const auto viewport = glContext.viewport.getCurrentValue(); + auto image = glContext.readFramebuffer<AlphaImage, gfx::TexturePixelType::Stencil>(viewport.size, false); // Scale the Stencil buffer to cover the entire color space. auto it = image.data.get(); @@ -502,9 +512,9 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { *it *= factor; } - parameters.context.pixelZoom = { 1, 1 }; - parameters.context.rasterPos = { -1, -1, 0, 1 }; - parameters.context.drawPixels(image); + glContext.pixelZoom = { 1, 1 }; + glContext.rasterPos = { -1, -1, 0, 1 }; + glContext.drawPixels(image); return; } @@ -565,39 +575,26 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { #if not MBGL_USE_GLES2 and not defined(NDEBUG) // Render the depth buffer. if (parameters.debugOptions & MapDebugOptions::DepthBuffer) { - parameters.context.setStencilMode(gfx::StencilMode::disabled()); - parameters.context.setDepthMode(gfx::DepthMode::disabled()); - parameters.context.setColorMode(gfx::ColorMode::unblended()); - parameters.context.program = 0; + glContext.setStencilMode(gfx::StencilMode::disabled()); + glContext.setDepthMode(gfx::DepthMode::disabled()); + glContext.setColorMode(gfx::ColorMode::unblended()); + glContext.program = 0; // Scales the values in the depth buffer so that they cover the entire grayscale range. This // makes it easier to spot tiny differences. const float base = 1.0f / (1.0f - parameters.depthRangeSize); - parameters.context.pixelTransferDepth = { base, 1.0f - base }; + glContext.pixelTransferDepth = { base, 1.0f - base }; // Read the stencil buffer - auto viewport = parameters.context.viewport.getCurrentValue(); - auto image = parameters.context.readFramebuffer<AlphaImage, gfx::TexturePixelType::Depth>(viewport.size, false); + auto viewport = glContext.viewport.getCurrentValue(); + auto image = glContext.readFramebuffer<AlphaImage, gfx::TexturePixelType::Depth>(viewport.size, false); - parameters.context.pixelZoom = { 1, 1 }; - parameters.context.rasterPos = { -1, -1, 0, 1 }; - parameters.context.drawPixels(image); + glContext.pixelZoom = { 1, 1 }; + glContext.rasterPos = { -1, -1, 0, 1 }; + glContext.drawPixels(image); } #endif - // TODO: Find a better way to unbind VAOs after we're done with them without introducing - // unnecessary bind(0)/bind(N) sequences. - { - MBGL_DEBUG_GROUP(parameters.context, "cleanup"); - - parameters.context.activeTextureUnit = 1; - parameters.context.texture[1] = 0; - parameters.context.activeTextureUnit = 0; - parameters.context.texture[0] = 0; - - parameters.context.bindVertexArray = 0; - } - observer->onDidFinishRenderingFrame( loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial, updateParameters.mode == MapMode::Continuous && hasTransitions(parameters.timePoint) @@ -614,6 +611,12 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { parameters.context.performCleanup(); } +void Renderer::Impl::flush() { + assert(BackendScope::exists()); + + backend.getContext().flush(); +} + std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options) const { std::vector<const RenderLayer*> layers; if (options.layerIDs) { @@ -837,4 +840,8 @@ void Renderer::Impl::onTileChanged(RenderSource&, const OverscaledTileID&) { observer->onInvalidate(); } +void Renderer::Impl::onStyleImageMissing(const std::string& id, std::function<void()> done) { + observer->onStyleImageMissing(id, std::move(done)); +} + } // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp index 05bf2e9b2b..624b4c273c 100644 --- a/src/mbgl/renderer/renderer_impl.hpp +++ b/src/mbgl/renderer/renderer_impl.hpp @@ -11,6 +11,7 @@ #include <mbgl/map/zoom_history.hpp> #include <mbgl/text/cross_tile_symbol_index.hpp> #include <mbgl/text/glyph_manager_observer.hpp> +#include <mbgl/renderer/image_manager_observer.hpp> #include <mbgl/text/placement.hpp> #include <memory> @@ -34,6 +35,7 @@ class LineAtlas; class CrossTileSymbolIndex; class Renderer::Impl : public GlyphManagerObserver, + public ImageManagerObserver, public RenderSourceObserver{ public: Impl(RendererBackend&, float pixelRatio_, Scheduler&, GLContextMode, @@ -48,6 +50,8 @@ public: void render(const UpdateParameters&); + void flush(); + std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&) const; std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const; std::vector<Feature> queryShapeAnnotations(const ScreenLineString&) const; @@ -84,6 +88,9 @@ private: void onTileChanged(RenderSource&, const OverscaledTileID&) override; void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override; + // ImageManagerObserver implementation + void onStyleImageMissing(const std::string&, std::function<void()>) override; + void updateFadingTiles(); friend class Renderer; diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp index 1b135a2838..dee3eab750 100644 --- a/src/mbgl/renderer/sources/render_image_source.cpp +++ b/src/mbgl/renderer/sources/render_image_source.cpp @@ -7,7 +7,7 @@ #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/render_static_data.hpp> #include <mbgl/programs/programs.hpp> -#include <mbgl/gl/context.hpp> +#include <mbgl/gfx/cull_face_mode.hpp> #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/util/tile_cover.hpp> #include <mbgl/util/logging.hpp> @@ -73,8 +73,8 @@ void RenderImageSource::finishRender(PaintParameters& parameters) { parameters.staticData.tileBorderSegments, programInstance.computeAllUniformValues( DebugProgram::LayoutUniformValues { - uniforms::u_matrix::Value( matrix ), - uniforms::u_color::Value( Color::red() ) + uniforms::matrix::Value( matrix ), + uniforms::color::Value( Color::red() ) }, paintAttributeData, properties, diff --git a/src/mbgl/storage/asset_file_source.hpp b/src/mbgl/storage/asset_file_source.hpp index 5d98b4e69e..cc15dbb60b 100644 --- a/src/mbgl/storage/asset_file_source.hpp +++ b/src/mbgl/storage/asset_file_source.hpp @@ -10,7 +10,7 @@ template <typename T> class Thread; class AssetFileSource : public FileSource { public: - AssetFileSource(const std::string& assetRoot); + AssetFileSource(const std::string& assetPath); ~AssetFileSource() override; std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override; diff --git a/src/mbgl/storage/file_source.cpp b/src/mbgl/storage/file_source.cpp new file mode 100644 index 0000000000..5854682771 --- /dev/null +++ b/src/mbgl/storage/file_source.cpp @@ -0,0 +1,37 @@ +#include <mbgl/storage/file_source.hpp> +#include <mbgl/storage/resource_options.hpp> +#include <mbgl/util/string.hpp> + +#include <mutex> +#include <map> + +namespace mbgl { + +std::shared_ptr<FileSource> FileSource::getSharedFileSource(const ResourceOptions& options) { + static std::mutex mutex; + static std::map<std::string, std::weak_ptr<mbgl::FileSource>> fileSources; + + std::lock_guard<std::mutex> lock(mutex); + + // Purge entries no longer in use. + for (auto it = fileSources.begin(); it != fileSources.end();) { + it = it->second.expired() ? fileSources.erase(it) : ++it; + } + + const uint64_t context = reinterpret_cast<uint64_t>(options.platformContext()); + const std::string key = options.baseURL() + '|' + options.accessToken() + '|' + options.cachePath() + '|' + util::toString(context); + + std::shared_ptr<mbgl::FileSource> fileSource; + auto tuple = fileSources.find(key); + if (tuple != fileSources.end()) { + fileSource = tuple->second.lock(); + } + + if (!fileSource) { + fileSources[key] = fileSource = createPlatformFileSource(options); + } + + return fileSource; +} + +} // namespace mbgl diff --git a/src/mbgl/storage/resource_options.cpp b/src/mbgl/storage/resource_options.cpp new file mode 100644 index 0000000000..c56a22540b --- /dev/null +++ b/src/mbgl/storage/resource_options.cpp @@ -0,0 +1,80 @@ +#include <mbgl/storage/resource_options.hpp> +#include <mbgl/util/constants.hpp> + +namespace mbgl { + +class ResourceOptions::Impl { +public: + std::string accessToken; + std::string baseURL = mbgl::util::API_BASE_URL; + std::string cachePath = ":memory:"; + std::string assetPath = "."; + uint64_t maximumSize = mbgl::util::DEFAULT_MAX_CACHE_SIZE; + void* platformContext = nullptr; +}; + +// These requires the complete type of Impl. +ResourceOptions::ResourceOptions() : impl_(std::make_unique<Impl>()) {} +ResourceOptions::~ResourceOptions() = default; +ResourceOptions::ResourceOptions(ResourceOptions&&) noexcept = default; +ResourceOptions::ResourceOptions(const ResourceOptions& other) : impl_(std::make_unique<Impl>(*other.impl_)) {} + +ResourceOptions ResourceOptions::clone() const { + return ResourceOptions(*this); +} + +ResourceOptions& ResourceOptions::withAccessToken(std::string token) { + impl_->accessToken = std::move(token); + return *this; +} + +const std::string& ResourceOptions::accessToken() const { + return impl_->accessToken; +} + +ResourceOptions& ResourceOptions::withBaseURL(std::string url) { + impl_->baseURL = std::move(url); + return *this; +} + +const std::string& ResourceOptions::baseURL() const { + return impl_->baseURL; +} + +ResourceOptions& ResourceOptions::withCachePath(std::string path) { + impl_->cachePath = std::move(path); + return *this; +} + +const std::string& ResourceOptions::cachePath() const { + return impl_->cachePath; +} + +ResourceOptions& ResourceOptions::withAssetPath(std::string path) { + impl_->assetPath = std::move(path); + return *this; +} + +const std::string& ResourceOptions::assetPath() const { + return impl_->assetPath; +} + +ResourceOptions& ResourceOptions::withMaximumCacheSize(uint64_t size) { + impl_->maximumSize = size; + return *this; +} + +uint64_t ResourceOptions::maximumCacheSize() const { + return impl_->maximumSize; +} + +ResourceOptions& ResourceOptions::withPlatformContext(void* context) { + impl_->platformContext = context; + return *this; +} + +void* ResourceOptions::platformContext() const { + return impl_->platformContext; +} + +} // namespace mbgl diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index bdc6371722..0fcaab433b 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -49,6 +49,27 @@ optional<T> Converter<T, typename std::enable_if_t<std::is_enum<T>::value>>::ope return *result; } +template <class T> +auto Converter<std::vector<T>, typename std::enable_if_t<std::is_enum<T>::value>>::operator()(const Convertible& value, Error& error) const -> optional<std::vector<T>> { + if (!isArray(value)) { + error.message = "value must be an array"; + return nullopt; + } + + std::vector<T> result; + result.reserve(arrayLength(value)); + + for (std::size_t i = 0; i < arrayLength(value); ++i) { + optional<T> enumItem = Converter<T>{}(arrayMember(value, i), error); + if (!enumItem) { + return nullopt; + } + result.push_back(*enumItem); + } + + return result; +} + template optional<AlignmentType> Converter<AlignmentType>::operator()(const Convertible&, Error&) const; template optional<CirclePitchScaleType> Converter<CirclePitchScaleType>::operator()(const Convertible&, Error&) const; template optional<HillshadeIlluminationAnchorType> Converter<HillshadeIlluminationAnchorType>::operator()(const Convertible&, Error&) const; @@ -64,6 +85,7 @@ template optional<TextJustifyType> Converter<TextJustifyType>::operator()(const template optional<TextTransformType> Converter<TextTransformType>::operator()(const Convertible&, Error&) const; template optional<TranslateAnchorType> Converter<TranslateAnchorType>::operator()(const Convertible&, Error&) const; template optional<VisibilityType> Converter<VisibilityType>::operator()(const Convertible&, Error&) const; +template optional<std::vector<TextVariableAnchorType>> Converter<std::vector<TextVariableAnchorType>>::operator()(const Convertible&, Error&) const; optional<Color> Converter<Color>::operator()(const Convertible& value, Error& error) const { optional<std::string> string = toString(value); diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index 79ad2fc7d8..df4decc73e 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -136,6 +136,8 @@ template optional<PropertyExpression<std::vector<std::string>>> convertFunctionToExpression<std::vector<std::string>>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolAnchorType>> convertFunctionToExpression<SymbolAnchorType>(const Convertible&, Error&, bool); +template optional<PropertyExpression<std::vector<TextVariableAnchorType>>> + convertFunctionToExpression<std::vector<TextVariableAnchorType>>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolPlacementType>> convertFunctionToExpression<SymbolPlacementType>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolZOrderType>> diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp index ff038908b6..6e1d747324 100644 --- a/src/mbgl/style/conversion/property_value.cpp +++ b/src/mbgl/style/conversion/property_value.cpp @@ -73,6 +73,7 @@ template optional<PropertyValue<LineJoinType>> Converter<PropertyValue<LineJoinT template optional<PropertyValue<Position>> Converter<PropertyValue<Position>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; template optional<PropertyValue<RasterResamplingType>> Converter<PropertyValue<RasterResamplingType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; template optional<PropertyValue<SymbolAnchorType>> Converter<PropertyValue<SymbolAnchorType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional<PropertyValue<std::vector<TextVariableAnchorType>>> Converter<PropertyValue<std::vector<TextVariableAnchorType>>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; template optional<PropertyValue<SymbolPlacementType>> Converter<PropertyValue<SymbolPlacementType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; template optional<PropertyValue<SymbolZOrderType>> Converter<PropertyValue<SymbolZOrderType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; template optional<PropertyValue<TextJustifyType>> Converter<PropertyValue<TextJustifyType>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; diff --git a/src/mbgl/style/expression/value.cpp b/src/mbgl/style/expression/value.cpp index 436ed83ecd..e826a8a3cc 100644 --- a/src/mbgl/style/expression/value.cpp +++ b/src/mbgl/style/expression/value.cpp @@ -166,6 +166,11 @@ mbgl::Value ValueConverter<mbgl::Value>::fromExpressionValue(const Value& value) } options.emplace("text-font", std::vector<mbgl::Value>{ std::string("literal"), fontStack }); } + + if (section.textColor) { + options.emplace("text-color", fromExpressionValue(*section.textColor)); + } + serialized.push_back(options); } return serialized; @@ -324,6 +329,9 @@ template struct ValueConverter<std::vector<float>>; template type::Type valueTypeToExpressionType<std::vector<std::string>>(); template struct ValueConverter<std::vector<std::string>>; +template type::Type valueTypeToExpressionType<std::vector<TextVariableAnchorType>>(); +template struct ValueConverter<std::vector<TextVariableAnchorType>>; + template type::Type valueTypeToExpressionType<AlignmentType>(); template struct ValueConverter<AlignmentType>; diff --git a/src/mbgl/style/image_impl.hpp b/src/mbgl/style/image_impl.hpp index 54b5e6487b..b2decbf781 100644 --- a/src/mbgl/style/image_impl.hpp +++ b/src/mbgl/style/image_impl.hpp @@ -34,5 +34,6 @@ enum class ImageType : bool { using ImageMap = std::unordered_map<std::string, Immutable<style::Image::Impl>>; using ImageDependencies = std::unordered_map<std::string, ImageType>; using ImageRequestPair = std::pair<ImageDependencies, uint64_t>; +using ImageVersionMap = std::unordered_map<std::string, uint32_t>; } // namespace mbgl diff --git a/src/mbgl/style/layers/circle_layer_properties.hpp b/src/mbgl/style/layers/circle_layer_properties.hpp index bc0c961e75..57caba9e3a 100644 --- a/src/mbgl/style/layers/circle_layer_properties.hpp +++ b/src/mbgl/style/layers/circle_layer_properties.hpp @@ -12,19 +12,19 @@ namespace mbgl { namespace style { -struct CircleRadius : DataDrivenPaintProperty<float, attributes::a_radius, uniforms::u_radius> { +struct CircleRadius : DataDrivenPaintProperty<float, attributes::radius, uniforms::radius> { static float defaultValue() { return 5; } }; -struct CircleColor : DataDrivenPaintProperty<Color, attributes::a_color, uniforms::u_color> { +struct CircleColor : DataDrivenPaintProperty<Color, attributes::color, uniforms::color> { static Color defaultValue() { return Color::black(); } }; -struct CircleBlur : DataDrivenPaintProperty<float, attributes::a_blur, uniforms::u_blur> { +struct CircleBlur : DataDrivenPaintProperty<float, attributes::blur, uniforms::blur> { static float defaultValue() { return 0; } }; -struct CircleOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, uniforms::u_opacity> { +struct CircleOpacity : DataDrivenPaintProperty<float, attributes::opacity, uniforms::opacity> { static float defaultValue() { return 1; } }; @@ -44,15 +44,15 @@ struct CirclePitchAlignment : PaintProperty<AlignmentType> { static AlignmentType defaultValue() { return AlignmentType::Viewport; } }; -struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::a_stroke_width, uniforms::u_stroke_width> { +struct CircleStrokeWidth : DataDrivenPaintProperty<float, attributes::stroke_width, uniforms::stroke_width> { static float defaultValue() { return 0; } }; -struct CircleStrokeColor : DataDrivenPaintProperty<Color, attributes::a_stroke_color, uniforms::u_stroke_color> { +struct CircleStrokeColor : DataDrivenPaintProperty<Color, attributes::stroke_color, uniforms::stroke_color> { static Color defaultValue() { return Color::black(); } }; -struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::a_stroke_opacity, uniforms::u_stroke_opacity> { +struct CircleStrokeOpacity : DataDrivenPaintProperty<float, attributes::stroke_opacity, uniforms::stroke_opacity> { static float defaultValue() { return 1; } }; diff --git a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp index 20cba699fe..a7799eee22 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_properties.hpp @@ -16,7 +16,7 @@ struct FillExtrusionOpacity : PaintProperty<float> { static float defaultValue() { return 1; } }; -struct FillExtrusionColor : DataDrivenPaintProperty<Color, attributes::a_color, uniforms::u_color> { +struct FillExtrusionColor : DataDrivenPaintProperty<Color, attributes::color, uniforms::color> { static Color defaultValue() { return Color::black(); } }; @@ -28,15 +28,15 @@ struct FillExtrusionTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -struct FillExtrusionPattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::a_pattern_to, uniforms::u_pattern_to, attributes::a_pattern_from, uniforms::u_pattern_from> { +struct FillExtrusionPattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::pattern_to, uniforms::pattern_to, attributes::pattern_from, uniforms::pattern_from> { static std::string defaultValue() { return ""; } }; -struct FillExtrusionHeight : DataDrivenPaintProperty<float, attributes::a_height, uniforms::u_height> { +struct FillExtrusionHeight : DataDrivenPaintProperty<float, attributes::height, uniforms::height> { static float defaultValue() { return 0; } }; -struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::a_base, uniforms::u_base> { +struct FillExtrusionBase : DataDrivenPaintProperty<float, attributes::base, uniforms::base> { static float defaultValue() { return 0; } }; diff --git a/src/mbgl/style/layers/fill_layer_properties.hpp b/src/mbgl/style/layers/fill_layer_properties.hpp index a20089ff2e..942733f2e1 100644 --- a/src/mbgl/style/layers/fill_layer_properties.hpp +++ b/src/mbgl/style/layers/fill_layer_properties.hpp @@ -16,15 +16,15 @@ struct FillAntialias : PaintProperty<bool> { static bool defaultValue() { return true; } }; -struct FillOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, uniforms::u_opacity> { +struct FillOpacity : DataDrivenPaintProperty<float, attributes::opacity, uniforms::opacity> { static float defaultValue() { return 1; } }; -struct FillColor : DataDrivenPaintProperty<Color, attributes::a_color, uniforms::u_color> { +struct FillColor : DataDrivenPaintProperty<Color, attributes::color, uniforms::color> { static Color defaultValue() { return Color::black(); } }; -struct FillOutlineColor : DataDrivenPaintProperty<Color, attributes::a_outline_color, uniforms::u_outline_color> { +struct FillOutlineColor : DataDrivenPaintProperty<Color, attributes::outline_color, uniforms::outline_color> { static Color defaultValue() { return {}; } }; @@ -36,7 +36,7 @@ struct FillTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -struct FillPattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::a_pattern_to, uniforms::u_pattern_to, attributes::a_pattern_from, uniforms::u_pattern_from> { +struct FillPattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::pattern_to, uniforms::pattern_to, attributes::pattern_from, uniforms::pattern_from> { static std::string defaultValue() { return ""; } }; diff --git a/src/mbgl/style/layers/heatmap_layer_properties.hpp b/src/mbgl/style/layers/heatmap_layer_properties.hpp index 4d49a52c72..ce00217b2e 100644 --- a/src/mbgl/style/layers/heatmap_layer_properties.hpp +++ b/src/mbgl/style/layers/heatmap_layer_properties.hpp @@ -12,11 +12,11 @@ namespace mbgl { namespace style { -struct HeatmapRadius : DataDrivenPaintProperty<float, attributes::a_radius, uniforms::u_radius> { +struct HeatmapRadius : DataDrivenPaintProperty<float, attributes::radius, uniforms::radius> { static float defaultValue() { return 30; } }; -struct HeatmapWeight : DataDrivenPaintProperty<float, attributes::a_weight, uniforms::u_weight> { +struct HeatmapWeight : DataDrivenPaintProperty<float, attributes::weight, uniforms::weight> { static float defaultValue() { return 1; } }; diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index fcae615fe0..201189c849 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -153,6 +153,9 @@ void <%- camelize(type) %>Layer::set<%- camelize(property.name) %>(<%- propertyV return; auto impl_ = mutableImpl(); impl_->paint.template get<<%- camelize(property.name) %>>().value = value; +<% if (property.name === 'line-width') { -%> + impl_->paint.template get<LineFloorWidth>().value = value; +<% } -%> baseImpl = std::move(impl_); observer->onLayerChanged(*this); } diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index 89dffdcd42..de647fbc07 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -37,6 +37,13 @@ struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> template<typename T> static bool hasOverride(const T& t) { return !!t.<%- camelizeWithLeadingLowercase(property.name) %>; }; <% } -%> }; +<% if (property.name === 'line-width') { -%> + +struct LineFloorWidth : DataDrivenPaintProperty<float, attributes::floorwidth, uniforms::floorwidth> { + using EvaluatorType = DataDrivenPropertyEvaluator<float, true>; + static float defaultValue() { return 1.0f; } +}; +<% } -%> <% } -%> <% } -%> @@ -52,6 +59,9 @@ class <%- camelize(type) %>LayoutProperties : public Properties< class <%- camelize(type) %>PaintProperties : public Properties< <% for (const property of paintProperties.slice(0, -1)) { -%> <%- camelize(property.name) %>, +<% if (property.name === 'line-width') { -%> + LineFloorWidth, +<% } -%> <% } -%> <%- camelize(paintProperties.slice(-1)[0].name) %> > {}; diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 643c294edf..0a20762697 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -248,6 +248,7 @@ void LineLayer::setLineWidth(PropertyValue<float> value) { return; auto impl_ = mutableImpl(); impl_->paint.template get<LineWidth>().value = value; + impl_->paint.template get<LineFloorWidth>().value = value; baseImpl = std::move(impl_); observer->onLayerChanged(*this); } diff --git a/src/mbgl/style/layers/line_layer_properties.hpp b/src/mbgl/style/layers/line_layer_properties.hpp index bab6e77ce5..33d7eddbe8 100644 --- a/src/mbgl/style/layers/line_layer_properties.hpp +++ b/src/mbgl/style/layers/line_layer_properties.hpp @@ -32,11 +32,11 @@ struct LineRoundLimit : LayoutProperty<float> { static float defaultValue() { return 1; } }; -struct LineOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, uniforms::u_opacity> { +struct LineOpacity : DataDrivenPaintProperty<float, attributes::opacity, uniforms::opacity> { static float defaultValue() { return 1; } }; -struct LineColor : DataDrivenPaintProperty<Color, attributes::a_color, uniforms::u_color> { +struct LineColor : DataDrivenPaintProperty<Color, attributes::color, uniforms::color> { static Color defaultValue() { return Color::black(); } }; @@ -48,19 +48,24 @@ struct LineTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -struct LineWidth : DataDrivenPaintProperty<float, attributes::a_width, uniforms::u_width> { +struct LineWidth : DataDrivenPaintProperty<float, attributes::width, uniforms::width> { static float defaultValue() { return 1; } }; -struct LineGapWidth : DataDrivenPaintProperty<float, attributes::a_gapwidth, uniforms::u_gapwidth> { +struct LineFloorWidth : DataDrivenPaintProperty<float, attributes::floorwidth, uniforms::floorwidth> { + using EvaluatorType = DataDrivenPropertyEvaluator<float, true>; + static float defaultValue() { return 1.0f; } +}; + +struct LineGapWidth : DataDrivenPaintProperty<float, attributes::gapwidth, uniforms::gapwidth> { static float defaultValue() { return 0; } }; -struct LineOffset : DataDrivenPaintProperty<float, attributes::a_offset, uniforms::u_offset> { +struct LineOffset : DataDrivenPaintProperty<float, attributes::offset, uniforms::offset> { static float defaultValue() { return 0; } }; -struct LineBlur : DataDrivenPaintProperty<float, attributes::a_blur, uniforms::u_blur> { +struct LineBlur : DataDrivenPaintProperty<float, attributes::blur, uniforms::blur> { static float defaultValue() { return 0; } }; @@ -68,7 +73,7 @@ struct LineDasharray : CrossFadedPaintProperty<std::vector<float>> { static std::vector<float> defaultValue() { return { }; } }; -struct LinePattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::a_pattern_to, uniforms::u_pattern_to, attributes::a_pattern_from, uniforms::u_pattern_from> { +struct LinePattern : CrossFadedDataDrivenPaintProperty<std::string, attributes::pattern_to, uniforms::pattern_to, attributes::pattern_from, uniforms::pattern_from> { static std::string defaultValue() { return ""; } }; @@ -88,6 +93,7 @@ class LinePaintProperties : public Properties< LineTranslate, LineTranslateAnchor, LineWidth, + LineFloorWidth, LineGapWidth, LineOffset, LineBlur, diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 75ed881058..1c56888f73 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -492,6 +492,38 @@ void SymbolLayer::setTextJustify(PropertyValue<TextJustifyType> value) { baseImpl = std::move(impl_); observer->onLayerChanged(*this); } +PropertyValue<float> SymbolLayer::getDefaultTextRadialOffset() { + return TextRadialOffset::defaultValue(); +} + +PropertyValue<float> SymbolLayer::getTextRadialOffset() const { + return impl().layout.get<TextRadialOffset>(); +} + +void SymbolLayer::setTextRadialOffset(PropertyValue<float> value) { + if (value == getTextRadialOffset()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get<TextRadialOffset>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} +PropertyValue<std::vector<TextVariableAnchorType>> SymbolLayer::getDefaultTextVariableAnchor() { + return TextVariableAnchor::defaultValue(); +} + +PropertyValue<std::vector<TextVariableAnchorType>> SymbolLayer::getTextVariableAnchor() const { + return impl().layout.get<TextVariableAnchor>(); +} + +void SymbolLayer::setTextVariableAnchor(PropertyValue<std::vector<TextVariableAnchorType>> value) { + if (value == getTextVariableAnchor()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get<TextVariableAnchor>() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} PropertyValue<SymbolAnchorType> SymbolLayer::getDefaultTextAnchor() { return TextAnchor::defaultValue(); } @@ -1325,6 +1357,8 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co TextLineHeight, TextLetterSpacing, TextJustify, + TextRadialOffset, + TextVariableAnchor, TextAnchor, TextMaxAngle, TextRotate, @@ -1364,6 +1398,8 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co { "text-line-height", static_cast<uint8_t>(Property::TextLineHeight) }, { "text-letter-spacing", static_cast<uint8_t>(Property::TextLetterSpacing) }, { "text-justify", static_cast<uint8_t>(Property::TextJustify) }, + { "text-radial-offset", static_cast<uint8_t>(Property::TextRadialOffset) }, + { "text-variable-anchor", static_cast<uint8_t>(Property::TextVariableAnchor) }, { "text-anchor", static_cast<uint8_t>(Property::TextAnchor) }, { "text-max-angle", static_cast<uint8_t>(Property::TextMaxAngle) }, { "text-rotate", static_cast<uint8_t>(Property::TextRotate) }, @@ -1525,7 +1561,7 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co } - if (property == Property::IconSize || property == Property::IconRotate || property == Property::TextSize || property == Property::TextMaxWidth || property == Property::TextLetterSpacing || property == Property::TextRotate) { + if (property == Property::IconSize || property == Property::IconRotate || property == Property::TextSize || property == Property::TextMaxWidth || property == Property::TextLetterSpacing || property == Property::TextRadialOffset || property == Property::TextRotate) { Error error; optional<PropertyValue<float>> typedValue = convert<PropertyValue<float>>(value, error, true, false); if (!typedValue) { @@ -1557,6 +1593,11 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co return nullopt; } + if (property == Property::TextRadialOffset) { + setTextRadialOffset(*typedValue); + return nullopt; + } + if (property == Property::TextRotate) { setTextRotate(*typedValue); return nullopt; @@ -1674,6 +1715,18 @@ optional<Error> SymbolLayer::setLayoutProperty(const std::string& name, const Co } + if (property == Property::TextVariableAnchor) { + Error error; + optional<PropertyValue<std::vector<TextVariableAnchorType>>> typedValue = convert<PropertyValue<std::vector<TextVariableAnchorType>>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextVariableAnchor(*typedValue); + return nullopt; + + } + if (property == Property::TextTransform) { Error error; optional<PropertyValue<TextTransformType>> typedValue = convert<PropertyValue<TextTransformType>>(value, error, true, false); diff --git a/src/mbgl/style/layers/symbol_layer_impl.hpp b/src/mbgl/style/layers/symbol_layer_impl.hpp index f937fccaa8..9b63e0e8d6 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.hpp +++ b/src/mbgl/style/layers/symbol_layer_impl.hpp @@ -3,9 +3,11 @@ #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> +#include <mbgl/style/expression/literal.hpp> #include <mbgl/style/expression/format_expression.hpp> #include <mbgl/style/expression/formatted.hpp> #include <mbgl/style/expression/format_section_override.hpp> +#include <mbgl/style/expression/value.hpp> namespace mbgl { namespace style { @@ -56,25 +58,57 @@ struct FormatSectionOverrides<TypeList<PaintProperty...>> { template<typename Property, typename FormattedProperty> static bool hasOverride(const FormattedProperty& formatted) { + + const auto checkLiteral = [] (const TextField::Type& literal) { + for (const auto& section : literal.sections) { + if (Property::hasOverride(section)) { + return true; + } + } + return false; + }; + return formatted.match( - [] (const TextField::Type& t) { - for (const auto& section : t.sections) { - if (Property::hasOverride(section)) { - return true; - } - } - return false; + [&checkLiteral] (const TextField::Type& literal) { + return checkLiteral(literal); }, - [] (const PropertyExpression<TextField::Type>& t) { - if (t.getExpression().getKind() == expression::Kind::FormatExpression) { - const auto* e = static_cast<const expression::FormatExpression*>(&t.getExpression()); - for (const auto& section : e->getSections()) { - if (Property::hasOverride(section)) { - return true; + [&checkLiteral] (const PropertyExpression<TextField::Type>& property) { + bool expressionHasOverrides = false; + const auto checkExpression = [&](const expression::Expression& e) { + if (expressionHasOverrides) { + return; + } + + if (e.getKind() == expression::Kind::Literal && + e.getType() == expression::type::Formatted) { + const auto* literalExpr = static_cast<const expression::Literal*>(&e); + const auto formattedValue = expression::fromExpressionValue<expression::Formatted>(literalExpr->getValue()); + if (formattedValue && checkLiteral(*formattedValue)) { + expressionHasOverrides = true; + } + return; + } + + if (e.getKind() == expression::Kind::FormatExpression) { + const auto* formatExpr = static_cast<const expression::FormatExpression*>(&e); + for (const auto& section : formatExpr->getSections()) { + if (Property::hasOverride(section)) { + expressionHasOverrides = true; + break; + } } } + }; + + // Check root property expression and return early. + checkExpression(property.getExpression()); + if (expressionHasOverrides) { + return true; } - return false; + + // Traverse thru children and check whether any of them have overrides. + property.getExpression().eachChild(checkExpression); + return expressionHasOverrides; }, [] (const auto&) { return false; diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index c352ab8e77..cf8a9ab0d0 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -147,6 +147,16 @@ struct TextJustify : DataDrivenLayoutProperty<TextJustifyType> { static TextJustifyType defaultValue() { return TextJustifyType::Center; } }; +struct TextRadialOffset : DataDrivenLayoutProperty<float> { + static constexpr const char *name() { return "text-radial-offset"; } + static float defaultValue() { return 0; } +}; + +struct TextVariableAnchor : LayoutProperty<std::vector<TextVariableAnchorType>> { + static constexpr const char *name() { return "text-variable-anchor"; } + static std::vector<TextVariableAnchorType> defaultValue() { return { }; } +}; + struct TextAnchor : DataDrivenLayoutProperty<SymbolAnchorType> { static constexpr const char *name() { return "text-anchor"; } static SymbolAnchorType defaultValue() { return SymbolAnchorType::Center; } @@ -197,23 +207,23 @@ struct TextOptional : LayoutProperty<bool> { static bool defaultValue() { return false; } }; -struct IconOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, uniforms::u_opacity> { +struct IconOpacity : DataDrivenPaintProperty<float, attributes::opacity, uniforms::opacity> { static float defaultValue() { return 1; } }; -struct IconColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color> { +struct IconColor : DataDrivenPaintProperty<Color, attributes::fill_color, uniforms::fill_color> { static Color defaultValue() { return Color::black(); } }; -struct IconHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color, uniforms::u_halo_color> { +struct IconHaloColor : DataDrivenPaintProperty<Color, attributes::halo_color, uniforms::halo_color> { static Color defaultValue() { return {}; } }; -struct IconHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width, uniforms::u_halo_width> { +struct IconHaloWidth : DataDrivenPaintProperty<float, attributes::halo_width, uniforms::halo_width> { static float defaultValue() { return 0; } }; -struct IconHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur, uniforms::u_halo_blur> { +struct IconHaloBlur : DataDrivenPaintProperty<float, attributes::halo_blur, uniforms::halo_blur> { static float defaultValue() { return 0; } }; @@ -225,26 +235,26 @@ struct IconTranslateAnchor : PaintProperty<TranslateAnchorType> { static TranslateAnchorType defaultValue() { return TranslateAnchorType::Map; } }; -struct TextOpacity : DataDrivenPaintProperty<float, attributes::a_opacity, uniforms::u_opacity> { +struct TextOpacity : DataDrivenPaintProperty<float, attributes::opacity, uniforms::opacity> { static float defaultValue() { return 1; } }; -struct TextColor : DataDrivenPaintProperty<Color, attributes::a_fill_color, uniforms::u_fill_color, true> { +struct TextColor : DataDrivenPaintProperty<Color, attributes::fill_color, uniforms::fill_color, true> { static Color defaultValue() { return Color::black(); } static constexpr const char *name() { return "text-color"; } static constexpr auto expressionType() { return expression::type::ColorType{}; }; template<typename T> static bool hasOverride(const T& t) { return !!t.textColor; }; }; -struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::a_halo_color, uniforms::u_halo_color> { +struct TextHaloColor : DataDrivenPaintProperty<Color, attributes::halo_color, uniforms::halo_color> { static Color defaultValue() { return {}; } }; -struct TextHaloWidth : DataDrivenPaintProperty<float, attributes::a_halo_width, uniforms::u_halo_width> { +struct TextHaloWidth : DataDrivenPaintProperty<float, attributes::halo_width, uniforms::halo_width> { static float defaultValue() { return 0; } }; -struct TextHaloBlur : DataDrivenPaintProperty<float, attributes::a_halo_blur, uniforms::u_halo_blur> { +struct TextHaloBlur : DataDrivenPaintProperty<float, attributes::halo_blur, uniforms::halo_blur> { static float defaultValue() { return 0; } }; @@ -284,6 +294,8 @@ class SymbolLayoutProperties : public Properties< TextLineHeight, TextLetterSpacing, TextJustify, + TextRadialOffset, + TextVariableAnchor, TextAnchor, TextMaxAngle, TextRotate, diff --git a/src/mbgl/style/sources/raster_dem_source.cpp b/src/mbgl/style/sources/raster_dem_source.cpp index dc9feb8eeb..bb745561b1 100644 --- a/src/mbgl/style/sources/raster_dem_source.cpp +++ b/src/mbgl/style/sources/raster_dem_source.cpp @@ -3,7 +3,6 @@ #include <mbgl/style/source_observer.hpp> #include <mbgl/style/conversion/json.hpp> #include <mbgl/style/conversion/tileset.hpp> -#include <mbgl/storage/file_source.hpp> #include <mbgl/util/mapbox.hpp> namespace mbgl { @@ -13,7 +12,5 @@ RasterDEMSource::RasterDEMSource(std::string id, variant<std::string, Tileset> u : RasterSource(std::move(id), urlOrTileset_, tileSize, SourceType::RasterDEM){ } - - } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index d65e9c9de2..fde5aa632d 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -254,6 +254,7 @@ bool Style::Impl::isLoaded() const { void Style::Impl::addImage(std::unique_ptr<style::Image> image) { images.remove(image->getID()); // We permit using addImage to update. images.add(std::move(image)); + observer->onUpdate(); } void Style::Impl::removeImage(const std::string& id) { diff --git a/src/mbgl/style/types.cpp b/src/mbgl/style/types.cpp index 51174cf152..889f6029e2 100644 --- a/src/mbgl/style/types.cpp +++ b/src/mbgl/style/types.cpp @@ -76,13 +76,14 @@ MBGL_DEFINE_ENUM(SymbolAnchorType, { { SymbolAnchorType::BottomLeft, "bottom-left" }, { SymbolAnchorType::BottomRight, "bottom-right" } }); - + MBGL_DEFINE_ENUM(SymbolZOrderType, { { SymbolZOrderType::ViewportY, "viewport-y" }, { SymbolZOrderType::Source, "source" } }); MBGL_DEFINE_ENUM(TextJustifyType, { + { TextJustifyType::Auto, "auto" }, { TextJustifyType::Center, "center" }, { TextJustifyType::Left, "left" }, { TextJustifyType::Right, "right" }, diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp index 90acb2b441..88e59bf51c 100644 --- a/src/mbgl/text/collision_index.cpp +++ b/src/mbgl/text/collision_index.cpp @@ -80,6 +80,7 @@ bool CollisionIndex::isInsideTile(const CollisionBox& box, const CollisionTileBo std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, + Point<float> shift, const mat4& posMatrix, const mat4& labelPlaneMatrix, const float textPixelRatio, @@ -95,10 +96,10 @@ std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, CollisionBox& box = feature.boxes.front(); const auto projectedPoint = projectAndGetPerspectiveRatio(posMatrix, box.anchor); const float tileToViewport = textPixelRatio * projectedPoint.second; - box.px1 = box.x1 * tileToViewport + projectedPoint.first.x; - box.py1 = box.y1 * tileToViewport + projectedPoint.first.y; - box.px2 = box.x2 * tileToViewport + projectedPoint.first.x; - box.py2 = box.y2 * tileToViewport + projectedPoint.first.y; + box.px1 = (box.x1 + shift.x) * tileToViewport + projectedPoint.first.x; + box.py1 = (box.y1 + shift.y) * tileToViewport + projectedPoint.first.y; + box.px2 = (box.x2 + shift.x) * tileToViewport + projectedPoint.first.x; + box.py2 = (box.y2 + shift.y) * tileToViewport + projectedPoint.first.y; if ((avoidEdges && !isInsideTile(box, *avoidEdges)) || diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp index dac0aa0bf7..dd160c945c 100644 --- a/src/mbgl/text/collision_index.hpp +++ b/src/mbgl/text/collision_index.hpp @@ -23,6 +23,7 @@ public: explicit CollisionIndex(const TransformState&); std::pair<bool,bool> placeFeature(CollisionFeature& feature, + Point<float> shift, const mat4& posMatrix, const mat4& labelPlaneMatrix, const float textPixelRatio, diff --git a/src/mbgl/text/glyph.hpp b/src/mbgl/text/glyph.hpp index c97b242c10..7d6415c057 100644 --- a/src/mbgl/text/glyph.hpp +++ b/src/mbgl/text/glyph.hpp @@ -78,15 +78,17 @@ enum class WritingModeType : uint8_t; class Shaping { public: - explicit Shaping() = default; - explicit Shaping(float x, float y, WritingModeType writingMode_) - : top(y), bottom(y), left(x), right(x), writingMode(writingMode_) {} + Shaping() = default; + explicit Shaping(float x, float y, WritingModeType writingMode_, std::size_t lineCount_) + : top(y), bottom(y), left(x), right(x), writingMode(writingMode_), lineCount(lineCount_) {} std::vector<PositionedGlyph> positionedGlyphs; float top = 0; float bottom = 0; float left = 0; float right = 0; WritingModeType writingMode; + std::size_t lineCount = 0u; + std::string text = {}; explicit operator bool() const { return !positionedGlyphs.empty(); } }; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 4cc12b0980..f6c4ac1eb6 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -1,10 +1,13 @@ #include <mbgl/text/placement.hpp> + +#include <mbgl/layout/symbol_layout.hpp> #include <mbgl/renderer/render_layer.hpp> #include <mbgl/renderer/layers/render_layer_symbol_interface.hpp> #include <mbgl/renderer/render_tile.hpp> #include <mbgl/tile/geometry_tile.hpp> #include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/renderer/bucket.hpp> +#include <mbgl/util/math.hpp> namespace mbgl { @@ -55,13 +58,18 @@ const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& s } } -Placement::Placement(const TransformState& state_, MapMode mapMode_, style::TransitionOptions transitionOptions_, const bool crossSourceCollisions) +Placement::Placement(const TransformState& state_, MapMode mapMode_, style::TransitionOptions transitionOptions_, const bool crossSourceCollisions, std::unique_ptr<Placement> prevPlacement_) : collisionIndex(state_) , state(state_) , mapMode(mapMode_) , transitionOptions(transitionOptions_) , collisionGroups(crossSourceCollisions) -{} + , prevPlacement(std::move(prevPlacement_)) +{ + if (prevPlacement) { + prevPlacement->prevPlacement.reset(); // Only hold on to one placement back + } +} void Placement::placeLayer(const RenderLayerSymbolInterface& symbolInterface, const mat4& projMatrix, bool showCollisionBoxes) { @@ -121,6 +129,19 @@ void Placement::placeLayer(const RenderLayerSymbolInterface& symbolInterface, co } } +namespace { +Point<float> calculateVariableLayoutOffset(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale) { + AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); + float shiftX = -(alignment.horizontalAlign - 0.5f) * width; + float shiftY = -(alignment.verticalAlign - 0.5f) * height; + Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset); + return Point<float>( + shiftX + offset.x * textBoxScale, + shiftY + offset.y * textBoxScale + ); +} +} // namespace + void Placement::placeLayerBucket( SymbolBucket& bucket, const mat4& posMatrix, @@ -161,8 +182,11 @@ void Placement::placeLayerBucket( // See https://github.com/mapbox/mapbox-gl-native/issues/12683 const bool alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || bucket.layout.get<style::IconOptional>()); const bool alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || bucket.layout.get<style::TextOptional>()); + std::vector<style::TextVariableAnchorType> variableTextAnchors = bucket.layout.get<style::TextVariableAnchor>(); + const bool rotateWithMap = bucket.layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map; + const bool pitchWithMap = bucket.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map; - for (auto& symbolInstance : bucket.symbolInstances) { + for (SymbolInstance& symbolInstance : bucket.symbolInstances) { if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) { if (holdingForFade) { @@ -175,30 +199,111 @@ void Placement::placeLayerBucket( bool placeText = false; bool placeIcon = false; bool offscreen = true; - - if (symbolInstance.placedTextIndex) { - PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*symbolInstance.placedTextIndex); + optional<size_t> horizontalTextIndex = symbolInstance.getDefaultHorizontalPlacedTextIndex(); + if (horizontalTextIndex) { + CollisionFeature& textCollisionFeature = symbolInstance.textCollisionFeature; + PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex); const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol); - - auto placed = collisionIndex.placeFeature(symbolInstance.textCollisionFeature, - posMatrix, textLabelPlaneMatrix, textPixelRatio, - placedSymbol, scale, fontSize, - bucket.layout.get<style::TextAllowOverlap>(), - bucket.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes, avoidEdges, collisionGroup.second); - placeText = placed.first; - offscreen &= placed.second; + if (variableTextAnchors.empty()) { + auto placed = collisionIndex.placeFeature(textCollisionFeature, {}, + posMatrix, textLabelPlaneMatrix, textPixelRatio, + placedSymbol, scale, fontSize, + bucket.layout.get<style::TextAllowOverlap>(), + pitchWithMap, + showCollisionBoxes, avoidEdges, collisionGroup.second); + placeText = placed.first; + offscreen &= placed.second; + } else if (!textCollisionFeature.alongLine && !textCollisionFeature.boxes.empty()) { + const CollisionBox& textBox = symbolInstance.textCollisionFeature.boxes[0]; + const float width = textBox.x2 - textBox.x1; + const float height = textBox.y2 - textBox.y1; + const float textBoxScale = symbolInstance.textBoxScale; + + // If this symbol was in the last placement, shift the previously used + // anchor to the front of the anchor list. + if (prevPlacement) { + auto prevOffset = prevPlacement->variableOffsets.find(symbolInstance.crossTileID); + if (prevOffset != prevPlacement->variableOffsets.end() && + variableTextAnchors.front() != prevOffset->second.anchor) { + std::vector<style::TextVariableAnchorType> filtered; + filtered.reserve(variableTextAnchors.size()); + filtered.push_back(prevOffset->second.anchor); + for (auto anchor : variableTextAnchors) { + if (anchor != prevOffset->second.anchor) { + filtered.push_back(anchor); + } + } + variableTextAnchors = std::move(filtered); + } + } + + for (auto anchor : variableTextAnchors) { + Point<float> shift = calculateVariableLayoutOffset(anchor, width, height, symbolInstance.radialTextOffset, textBoxScale); + if (rotateWithMap) { + float angle = pitchWithMap ? state.getBearing() : -state.getBearing(); + shift = util::rotate(shift, angle); + } + + auto placed = collisionIndex.placeFeature(textCollisionFeature, shift, + posMatrix, mat4(), textPixelRatio, + placedSymbol, scale, fontSize, + bucket.layout.get<style::TextAllowOverlap>(), + pitchWithMap, + showCollisionBoxes, avoidEdges, collisionGroup.second); + + if (placed.first) { + assert(symbolInstance.crossTileID != 0u); + optional<style::TextVariableAnchorType> prevAnchor; + + // If this label was placed in the previous placement, record the anchor position + // to allow us to animate the transition + if (prevPlacement) { + auto prevOffset = prevPlacement->variableOffsets.find(symbolInstance.crossTileID); + auto prevPlacements = prevPlacement->placements.find(symbolInstance.crossTileID); + if (prevOffset != prevPlacement->variableOffsets.end() && + prevPlacements != prevPlacement->placements.end() && + prevPlacements->second.text) { + prevAnchor = prevOffset->second.anchor; + } + } + + variableOffsets.insert(std::make_pair(symbolInstance.crossTileID, VariableOffset{ + symbolInstance.radialTextOffset, + width, + height, + anchor, + textBoxScale, + prevAnchor + })); + markUsedJustification(bucket, anchor, symbolInstance); + + placeText = placed.first; + offscreen &= placed.second; + break; + } + } + + // If we didn't get placed, we still need to copy our position from the last placement for + // fade animations + if (prevPlacement && variableOffsets.find(symbolInstance.crossTileID) == variableOffsets.end()) { + auto prevOffset = prevPlacement->variableOffsets.find(symbolInstance.crossTileID); + if (prevOffset != prevPlacement->variableOffsets.end()) { + variableOffsets[symbolInstance.crossTileID] = prevOffset->second; + markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance); + } + } + } } if (symbolInstance.placedIconIndex) { PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex); const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol); - auto placed = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, + auto placed = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, {}, posMatrix, iconLabelPlaneMatrix, textPixelRatio, placedSymbol, scale, fontSize, bucket.layout.get<style::IconAllowOverlap>(), - bucket.layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, + pitchWithMap, showCollisionBoxes, avoidEdges, collisionGroup.second); placeIcon = placed.first; offscreen &= placed.second; @@ -240,7 +345,8 @@ void Placement::placeLayerBucket( bucket.justReloaded = false; } -void Placement::commit(const Placement& prevPlacement, TimePoint now) { +void Placement::commit(TimePoint now) { + assert(prevPlacement); commitTime = now; bool placementChanged = false; @@ -248,13 +354,13 @@ void Placement::commit(const Placement& prevPlacement, TimePoint now) { float increment = mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions && transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) > Milliseconds(0) ? - std::chrono::duration<float>(commitTime - prevPlacement.commitTime) / transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) : + std::chrono::duration<float>(commitTime - prevPlacement->commitTime) / transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) : 1.0; // add the opacities from the current placement, and copy their current values from the previous placement for (auto& jointPlacement : placements) { - auto prevOpacity = prevPlacement.opacities.find(jointPlacement.first); - if (prevOpacity != prevPlacement.opacities.end()) { + auto prevOpacity = prevPlacement->opacities.find(jointPlacement.first); + if (prevOpacity != prevPlacement->opacities.end()) { opacities.emplace(jointPlacement.first, JointOpacityState(prevOpacity->second, increment, jointPlacement.second.text, jointPlacement.second.icon)); placementChanged = placementChanged || jointPlacement.second.icon != prevOpacity->second.icon.placed || @@ -266,7 +372,7 @@ void Placement::commit(const Placement& prevPlacement, TimePoint now) { } // copy and update values from the previous placement that aren't in the current placement but haven't finished fading - for (auto& prevOpacity : prevPlacement.opacities) { + for (auto& prevOpacity : prevPlacement->opacities) { if (opacities.find(prevOpacity.first) == opacities.end()) { JointOpacityState jointOpacity(prevOpacity.second, increment, false, false); if (!jointOpacity.isHidden()) { @@ -276,7 +382,16 @@ void Placement::commit(const Placement& prevPlacement, TimePoint now) { } } - fadeStartTime = placementChanged ? commitTime : prevPlacement.fadeStartTime; + for (auto& prevOffset : prevPlacement->variableOffsets) { + const uint32_t crossTileID = prevOffset.first; + auto foundOffset = variableOffsets.find(crossTileID); + auto foundOpacity = opacities.find(crossTileID); + if (foundOffset == variableOffsets.end() && foundOpacity != opacities.end() && !foundOpacity->second.isHidden()) { + variableOffsets[prevOffset.first] = prevOffset.second; + } + } + + fadeStartTime = placementChanged ? commitTime : prevPlacement->fadeStartTime; } void Placement::updateLayerOpacities(const RenderLayerSymbolInterface& symbolInterface) { @@ -310,7 +425,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& const bool textAllowOverlap = bucket.layout.get<style::TextAllowOverlap>(); const bool iconAllowOverlap = bucket.layout.get<style::IconAllowOverlap>(); - + const bool variablePlacement = !bucket.layout.get<style::TextVariableAnchor>().empty(); + const bool rotateWithMap = bucket.layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map; + const bool pitchWithMap = bucket.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map; + // If allow-overlap is true, we can show symbols before placement runs on them // But we have to wait for placement if we potentially depend on a paired icon/text // with allow-overlap: false. @@ -339,18 +457,38 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& if (symbolInstance.hasText) { auto opacityVertex = SymbolSDFTextProgram::opacityVertex(opacityState.text.placed, opacityState.text.opacity); - for (size_t i = 0; i < symbolInstance.horizontalGlyphQuads.size() * 4; i++) { - bucket.text.opacityVertices.emplace_back(opacityVertex); + if (symbolInstance.placedRightTextIndex) { + for (size_t i = 0; i < symbolInstance.rightJustifiedGlyphQuads.size() * 4; i++) { + bucket.text.opacityVertices.emplace_back(opacityVertex); + } + PlacedSymbol& placed = bucket.text.placedSymbols[*symbolInstance.placedRightTextIndex]; + placed.hidden = opacityState.isHidden(); } - for (size_t i = 0; i < symbolInstance.verticalGlyphQuads.size() * 4; i++) { - bucket.text.opacityVertices.emplace_back(opacityVertex); + if (symbolInstance.placedCenterTextIndex && !symbolInstance.singleLine) { + for (size_t i = 0; i < symbolInstance.centerJustifiedGlyphQuads.size() * 4; i++) { + bucket.text.opacityVertices.emplace_back(opacityVertex); + } + PlacedSymbol& placed = bucket.text.placedSymbols[*symbolInstance.placedCenterTextIndex]; + placed.hidden = opacityState.isHidden(); } - if (symbolInstance.placedTextIndex) { - bucket.text.placedSymbols[*symbolInstance.placedTextIndex].hidden = opacityState.isHidden(); + if (symbolInstance.placedLeftTextIndex && !symbolInstance.singleLine) { + for (size_t i = 0; i < symbolInstance.leftJustifiedGlyphQuads.size() * 4; i++) { + bucket.text.opacityVertices.emplace_back(opacityVertex); + } + PlacedSymbol& placed = bucket.text.placedSymbols[*symbolInstance.placedLeftTextIndex]; + placed.hidden = opacityState.isHidden(); } if (symbolInstance.placedVerticalTextIndex) { + for (size_t i = 0; i < symbolInstance.verticalGlyphQuads.size() * 4; i++) { + bucket.text.opacityVertices.emplace_back(opacityVertex); + } bucket.text.placedSymbols[*symbolInstance.placedVerticalTextIndex].hidden = opacityState.isHidden(); } + + auto prevOffset = variableOffsets.find(symbolInstance.crossTileID); + if (prevOffset != variableOffsets.end()) { + markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance); + } } if (symbolInstance.hasIcon) { auto opacityVertex = SymbolIconProgram::opacityVertex(opacityState.icon.placed, opacityState.icon.opacity); @@ -369,7 +507,42 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& if (feature.alongLine) { return; } - auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false); + auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false, {}); + for (size_t i = 0; i < feature.boxes.size() * 4; i++) { + bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); + } + }; + + auto updateCollisionTextBox = [this, &bucket, &symbolInstance, variablePlacement, rotateWithMap, pitchWithMap](const auto& feature, const bool placed) { + if (feature.alongLine) { + return; + } + Point<float> shift; + bool used = true; + if (variablePlacement) { + auto foundOffset = variableOffsets.find(symbolInstance.crossTileID); + if (foundOffset != variableOffsets.end()) { + const VariableOffset& variableOffset = foundOffset->second; + // This will show either the currently placed position or the last + // successfully placed position (so you can visualize what collision + // just made the symbol disappear, and the most likely place for the + // symbol to come back) + shift = calculateVariableLayoutOffset(variableOffset.anchor, + variableOffset.width, + variableOffset.height, + variableOffset.radialOffset, + variableOffset.textBoxScale); + if (rotateWithMap) { + shift = util::rotate(shift, pitchWithMap ? state.getBearing() : -state.getBearing()); + } + } else { + // No offset -> this symbol hasn't been placed since coming on-screen + // No single box is particularly meaningful and all of them would be too noisy + // Use the center box just to show something's there, but mark it "not used" + used = false; + } + } + auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !used, shift); for (size_t i = 0; i < feature.boxes.size() * 4; i++) { bucket.collisionBox.dynamicVertices.emplace_back(dynamicVertex); } @@ -380,7 +553,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& return; } for (const CollisionBox& box : feature.boxes) { - auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !box.used); + auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !box.used, {}); bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); bucket.collisionCircle.dynamicVertices.emplace_back(dynamicVertex); @@ -389,7 +562,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& }; if (bucket.hasCollisionBoxData()) { - updateCollisionBox(symbolInstance.textCollisionFeature, opacityState.text.placed); + updateCollisionTextBox(symbolInstance.textCollisionFeature, opacityState.text.placed); updateCollisionBox(symbolInstance.iconCollisionFeature, opacityState.icon.placed); } if (bucket.hasCollisionCircleData()) { @@ -406,6 +579,31 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>& } } +void Placement::markUsedJustification(SymbolBucket& bucket, style::TextVariableAnchorType placedAnchor, SymbolInstance& symbolInstance) { + std::map<style::TextJustifyType, optional<size_t>> justificationToIndex { + {style::TextJustifyType::Right, symbolInstance.placedRightTextIndex}, + {style::TextJustifyType::Center, symbolInstance.placedCenterTextIndex}, + {style::TextJustifyType::Left, symbolInstance.placedLeftTextIndex}, + }; + style::TextJustifyType justify = getAnchorJustification(placedAnchor); + assert(justify == style::TextJustifyType::Right || justify == style::TextJustifyType::Center || justify == style::TextJustifyType::Left); + const optional<size_t> autoIndex = justificationToIndex[justify]; + + for (auto& pair : justificationToIndex) { + const optional<size_t> index = pair.second; + if (index) { + assert(bucket.text.placedSymbols.size() > *index); + if (autoIndex && *index != *autoIndex) { + // There are multiple justifications and this one isn't it: shift offscreen + bucket.text.placedSymbols.at(*index).crossTileID = 0u; + } else { + // Either this is the chosen justification or the justification is hardwired: use this one + bucket.text.placedSymbols.at(*index).crossTileID = symbolInstance.crossTileID; + } + } + } +} + float Placement::symbolFadeChange(TimePoint now) const { if (mapMode == MapMode::Continuous && transitionOptions.enablePlacementTransitions && transitionOptions.duration.value_or(util::DEFAULT_TRANSITION_DURATION) > Milliseconds(0)) { diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index cc23110e54..3f2a7b8a03 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -12,6 +12,7 @@ namespace mbgl { class RenderLayerSymbolInterface; class SymbolBucket; +class SymbolInstance; class OpacityState { public: @@ -31,6 +32,16 @@ public: OpacityState text; }; +class VariableOffset { +public: + float radialOffset; + float width; + float height; + style::TextVariableAnchorType anchor; + float textBoxScale; + optional<style::TextVariableAnchorType> prevAnchor; +}; + class JointPlacement { public: JointPlacement(bool text_, bool icon_, bool skipFade_) @@ -45,7 +56,7 @@ public: // visible right away. const bool skipFade; }; - + struct RetainedQueryData { uint32_t bucketInstanceId; std::shared_ptr<FeatureIndex> featureIndex; @@ -80,9 +91,9 @@ private: class Placement { public: - Placement(const TransformState&, MapMode, style::TransitionOptions, const bool crossSourceCollisions); + Placement(const TransformState&, MapMode, style::TransitionOptions, const bool crossSourceCollisions, std::unique_ptr<Placement> prevPlacementOrNull = nullptr); void placeLayer(const RenderLayerSymbolInterface&, const mat4&, bool showCollisionBoxes); - void commit(const Placement& prevPlacement, TimePoint); + void commit(TimePoint); void updateLayerOpacities(const RenderLayerSymbolInterface&); float symbolFadeChange(TimePoint now) const; bool hasTransitions(TimePoint now) const; @@ -94,8 +105,10 @@ public: void setStale(); const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const; -private: + using VariableOffsets = std::reference_wrapper<const std::unordered_map<uint32_t, VariableOffset>>; + VariableOffsets getVariableOffsets() const { return std::cref(variableOffsets); } +private: void placeLayerBucket( SymbolBucket&, const mat4& posMatrix, @@ -109,6 +122,7 @@ private: const CollisionGroups::CollisionGroup& collisionGroup); void updateBucketOpacities(SymbolBucket&, std::set<uint32_t>&); + void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, SymbolInstance&); CollisionIndex collisionIndex; @@ -121,11 +135,13 @@ private: std::unordered_map<uint32_t, JointPlacement> placements; std::unordered_map<uint32_t, JointOpacityState> opacities; + std::unordered_map<uint32_t, VariableOffset> variableOffsets; bool stale = false; std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData; CollisionGroups collisionGroups; + std::unique_ptr<Placement> prevPlacement; }; } // namespace mbgl diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index ec0045caad..6be5d8c01e 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -92,16 +92,12 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, } SymbolQuads getGlyphQuads(const Shaping& shapedText, + const std::array<float, 2> textOffset, const SymbolLayoutProperties::Evaluated& layout, const style::SymbolPlacementType placement, const GlyphPositions& positions) { const float textRotate = layout.get<TextRotate>() * util::DEG2RAD; - const float oneEm = 24.0; - std::array<float, 2> textOffset = layout.get<TextOffset>(); - textOffset[0] *= oneEm; - textOffset[1] *= oneEm; - SymbolQuads quads; for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) { diff --git a/src/mbgl/text/quads.hpp b/src/mbgl/text/quads.hpp index f41a4fec66..0bb892e4d1 100644 --- a/src/mbgl/text/quads.hpp +++ b/src/mbgl/text/quads.hpp @@ -49,6 +49,7 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, const Shaping& shapedText); SymbolQuads getGlyphQuads(const Shaping& shapedText, + const std::array<float, 2> textOffset, const style::SymbolLayoutProperties::Evaluated&, style::SymbolPlacementType placement, const GlyphPositions& positions); diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 02dbf146e1..ba21b97389 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -1,4 +1,5 @@ #include <mbgl/text/shaping.hpp> +#include <mbgl/util/constants.hpp> #include <mbgl/util/i18n.hpp> #include <mbgl/layout/symbol_feature.hpp> #include <mbgl/math/minmax.hpp> @@ -10,58 +11,61 @@ namespace mbgl { -struct AnchorAlignment { - AnchorAlignment(float horizontal_, float vertical_) - : horizontalAlign(horizontal_), verticalAlign(vertical_) { - } - - float horizontalAlign; - float verticalAlign; -}; -AnchorAlignment getAnchorAlignment(style::SymbolAnchorType anchor) { - float horizontalAlign = 0.5; - float verticalAlign = 0.5; +// static +AnchorAlignment AnchorAlignment::getAnchorAlignment(style::SymbolAnchorType anchor) { + AnchorAlignment result(0.5f, 0.5f); switch (anchor) { - case style::SymbolAnchorType::Top: - case style::SymbolAnchorType::Bottom: - case style::SymbolAnchorType::Center: - break; case style::SymbolAnchorType::Right: case style::SymbolAnchorType::TopRight: case style::SymbolAnchorType::BottomRight: - horizontalAlign = 1; + result.horizontalAlign = 1.0f; break; case style::SymbolAnchorType::Left: case style::SymbolAnchorType::TopLeft: case style::SymbolAnchorType::BottomLeft: - horizontalAlign = 0; + result.horizontalAlign = 0.0f; break; + default: + break; } switch (anchor) { - case style::SymbolAnchorType::Left: - case style::SymbolAnchorType::Right: - case style::SymbolAnchorType::Center: - break; case style::SymbolAnchorType::Bottom: case style::SymbolAnchorType::BottomLeft: case style::SymbolAnchorType::BottomRight: - verticalAlign = 1; + result.verticalAlign = 1.0f; break; case style::SymbolAnchorType::Top: case style::SymbolAnchorType::TopLeft: case style::SymbolAnchorType::TopRight: - verticalAlign = 0; + result.verticalAlign = 0.0f; + break; + default: break; } - return AnchorAlignment(horizontalAlign, verticalAlign); + return result; +} + +style::TextJustifyType getAnchorJustification(style::SymbolAnchorType anchor) { + switch (anchor) { + case style::SymbolAnchorType::Right: + case style::SymbolAnchorType::TopRight: + case style::SymbolAnchorType::BottomRight: + return style::TextJustifyType::Right; + case style::SymbolAnchorType::Left: + case style::SymbolAnchorType::TopLeft: + case style::SymbolAnchorType::BottomLeft: + return style::TextJustifyType::Left; + default: + return style::TextJustifyType::Center; + } } PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, const std::array<float, 2>& iconOffset, style::SymbolAnchorType iconAnchor, const float iconRotation) { - AnchorAlignment anchorAlign = getAnchorAlignment(iconAnchor); + AnchorAlignment anchorAlign = AnchorAlignment::getAnchorAlignment(iconAnchor); float dx = iconOffset[0]; float dy = iconOffset[1]; float x1 = dx - image.displaySize()[0] * anchorAlign.horizontalAlign; @@ -269,7 +273,6 @@ void shapeLines(Shaping& shaping, const float lineHeight, const style::SymbolAnchorType textAnchor, const style::TextJustifyType textJustify, - const float verticalHeight, const WritingModeType writingMode, const GlyphMap& glyphMap) { @@ -314,7 +317,7 @@ void shapeLines(Shaping& shaping, // We don't know the baseline, but since we're laying out // at 24 points, we can calculate how much it will move when // we scale up or down. - const double baselineOffset = (lineMaxScale - section.scale) * 24; + const double baselineOffset = (lineMaxScale - section.scale) * util::ONE_EM; const Glyph& glyph = **it->second; @@ -323,7 +326,7 @@ void shapeLines(Shaping& shaping, x += glyph.metrics.advance * section.scale + spacing; } else { shaping.positionedGlyphs.emplace_back(codePoint, x, baselineOffset, true, section.fontStackHash, section.scale, sectionIndex); - x += verticalHeight * section.scale + spacing; + x += util::ONE_EM * section.scale + spacing; } } @@ -340,7 +343,7 @@ void shapeLines(Shaping& shaping, y += lineHeight * lineMaxScale; } - auto anchorAlign = getAnchorAlignment(textAnchor); + auto anchorAlign = AnchorAlignment::getAnchorAlignment(textAnchor); align(shaping, justify, anchorAlign.horizontalAlign, anchorAlign.verticalAlign, maxLineLength, lineHeight, lines.size()); @@ -360,12 +363,9 @@ const Shaping getShaping(const TaggedString& formattedString, const style::TextJustifyType textJustify, const float spacing, const Point<float>& translate, - const float verticalHeight, const WritingModeType writingMode, BiDi& bidi, - const GlyphMap& glyphs) { - Shaping shaping(translate.x, translate.y, writingMode); - + const GlyphMap& glyphs) { std::vector<TaggedString> reorderedLines; if (formattedString.sectionCount() == 1) { auto untaggedLines = bidi.processText(formattedString.rawText(), @@ -380,9 +380,9 @@ const Shaping getShaping(const TaggedString& formattedString, reorderedLines.emplace_back(line, formattedString.getSections()); } } - + Shaping shaping(translate.x, translate.y, writingMode, reorderedLines.size()); shapeLines(shaping, reorderedLines, spacing, lineHeight, textAnchor, - textJustify, verticalHeight, writingMode, glyphs); + textJustify, writingMode, glyphs); return shaping; } diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 50ac893098..766b1ce233 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -7,6 +7,20 @@ namespace mbgl { +struct AnchorAlignment { + AnchorAlignment(float horizontal, float vertical) + : horizontalAlign(horizontal), verticalAlign(vertical) { + } + + static AnchorAlignment getAnchorAlignment(style::SymbolAnchorType anchor); + + float horizontalAlign; + float verticalAlign; +}; + +// Choose the justification that matches the direction of the TextAnchor +style::TextJustifyType getAnchorJustification(style::SymbolAnchorType anchor); + class SymbolFeature; class BiDi; @@ -53,7 +67,6 @@ const Shaping getShaping(const TaggedString& string, style::TextJustifyType textJustify, float spacing, const Point<float>& translate, - float verticalHeight, const WritingModeType, BiDi& bidi, const GlyphMap& glyphs); diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index c8498976b8..9165c03267 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -13,7 +13,6 @@ #include <mbgl/renderer/query.hpp> #include <mbgl/text/glyph_atlas.hpp> #include <mbgl/renderer/image_atlas.hpp> -#include <mbgl/storage/file_source.hpp> #include <mbgl/geometry/feature_index.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/util/logging.hpp> @@ -157,8 +156,8 @@ void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { glyphManager.getGlyphs(*this, std::move(glyphDependencies)); } -void GeometryTile::onImagesAvailable(ImageMap images, ImageMap patterns, uint64_t imageCorrelationID) { - worker.self().invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), std::move(patterns), imageCorrelationID); +void GeometryTile::onImagesAvailable(ImageMap images, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) { + worker.self().invoke(&GeometryTileWorker::onImagesAvailable, std::move(images), std::move(patterns), std::move(versionMap), imageCorrelationID); } void GeometryTile::getImages(ImageRequestPair pair) { @@ -193,6 +192,10 @@ void GeometryTile::upload(gfx::Context& context) { iconAtlasTexture = context.createTexture(iconAtlas.image); iconAtlas.image = {}; } + + if (iconAtlasTexture) { + iconAtlas.patchUpdatedImages(context, *iconAtlasTexture, imageManager); + } } Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const { diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index b652e7ba5d..53a8910c27 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -37,7 +37,7 @@ public: void setShowCollisionBoxes(const bool showCollisionBoxes) override; void onGlyphsAvailable(GlyphMap) override; - void onImagesAvailable(ImageMap, ImageMap, uint64_t imageCorrelationID) override; + void onImagesAvailable(ImageMap, ImageMap, ImageVersionMap versionMap, uint64_t imageCorrelationID) override; void getGlyphs(GlyphDependencies); void getImages(ImageRequestPair); diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 943e782af1..0b703cd68b 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -278,12 +278,13 @@ void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { symbolDependenciesChanged(); } -void GeometryTileWorker::onImagesAvailable(ImageMap newIconMap, ImageMap newPatternMap, uint64_t imageCorrelationID_) { +void GeometryTileWorker::onImagesAvailable(ImageMap newIconMap, ImageMap newPatternMap, ImageVersionMap newVersionMap, uint64_t imageCorrelationID_) { if (imageCorrelationID != imageCorrelationID_) { return; // Ignore outdated image request replies. } imageMap = std::move(newIconMap); patternMap = std::move(newPatternMap); + versionMap = std::move(newVersionMap); pendingImageDependencies.clear(); symbolDependenciesChanged(); } @@ -441,7 +442,7 @@ void GeometryTileWorker::finalizeLayout() { MBGL_TIMING_START(watch) optional<AlphaImage> glyphAtlasImage; - ImageAtlas iconAtlas = makeImageAtlas(imageMap, patternMap); + ImageAtlas iconAtlas = makeImageAtlas(imageMap, patternMap, versionMap); if (!layouts.empty()) { GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); glyphAtlasImage = std::move(glyphAtlas.image); diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 485d1315a6..706bac0154 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -44,7 +44,7 @@ public: void setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_); void onGlyphsAvailable(GlyphMap glyphs); - void onImagesAvailable(ImageMap icons, ImageMap patterns, uint64_t imageCorrelationID); + void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID); private: void coalesced(); @@ -96,6 +96,7 @@ private: GlyphMap glyphMap; ImageMap imageMap; ImageMap patternMap; + ImageVersionMap versionMap; bool showCollisionBoxes; bool firstLoad = true; diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp index ba961853d0..224c5c9062 100644 --- a/src/mbgl/tile/raster_dem_tile.cpp +++ b/src/mbgl/tile/raster_dem_tile.cpp @@ -5,7 +5,6 @@ #include <mbgl/style/source.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/storage/response.hpp> -#include <mbgl/storage/file_source.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/buckets/hillshade_bucket.hpp> #include <mbgl/actor/scheduler.hpp> diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp index 22561ec11d..ff02301021 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -5,7 +5,6 @@ #include <mbgl/style/source.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/storage/response.hpp> -#include <mbgl/storage/file_source.hpp> #include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/renderer/buckets/raster_bucket.hpp> #include <mbgl/actor/scheduler.hpp> diff --git a/src/mbgl/util/literal.hpp b/src/mbgl/util/literal.hpp new file mode 100644 index 0000000000..d4fec49b35 --- /dev/null +++ b/src/mbgl/util/literal.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include <utility> +#include <cstddef> + +namespace mbgl { + +// Using structs instead of constexpr templates because GCC 4.9 doesn't support these yet. + +template <char... Cs> +struct string_literal { + static constexpr const char chars[] = { Cs..., 0 }; + + static constexpr const char* value() { + return chars; + } +}; + +template <char... Cs> +constexpr const char string_literal<Cs...>::chars[]; + +namespace detail { + +using string_fn = const char* (*)(); + +template <string_fn name, std::size_t... Is> +string_literal<name()[Is]...> to_string_literal(std::index_sequence<Is...>); + +constexpr std::size_t string_length(const char* const str, std::size_t len = 0) { + return str[0] ? string_length(str + 1, len + 1) : len; +} + +template <class...> +struct concat_literals; + +template <> +struct concat_literals<> { + static constexpr auto value() { + return ""; + } +}; + +template <char... As, char... Bs, class... Rest> +struct concat_literals<string_literal<As...>, string_literal<Bs...>, Rest...> { + static constexpr auto value() { + return concat_literals<string_literal<As..., Bs...>, Rest...>::value(); + } +}; + +template <char... Cs> +struct concat_literals<string_literal<Cs...>> { + static constexpr auto value() { + return string_literal<Cs...>::value(); + } +}; + +} // namespace detail + +template <detail::string_fn... str> +struct concat_literals { + static constexpr auto value() { + return detail::concat_literals<decltype(detail::to_string_literal<str>( + std::make_index_sequence<detail::string_length(str())>()))...>::value(); + } +}; + +} // namespace mbgl diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 2a58ff86a3..6bc09c7b16 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -62,18 +62,20 @@ private: const gfx::TextureChannelDataType type; }; -OffscreenTexture::OffscreenTexture(gl::Context& context, +OffscreenTexture::OffscreenTexture(gfx::Context& context, const Size size, const gfx::TextureChannelDataType type) - : impl(std::make_unique<Impl>(context, std::move(size), type)) { + // TODO: remove cast + : impl(std::make_unique<Impl>(reinterpret_cast<gl::Context&>(context), std::move(size), type)) { assert(!size.isEmpty()); } -OffscreenTexture::OffscreenTexture(gl::Context& context, +OffscreenTexture::OffscreenTexture(gfx::Context& context, const Size size, gl::Renderbuffer<gl::RenderbufferType::DepthComponent>& renderbuffer, const gfx::TextureChannelDataType type) - : impl(std::make_unique<Impl>(context, std::move(size), renderbuffer, type)) { + // TODO: remove cast + : impl(std::make_unique<Impl>(reinterpret_cast<gl::Context&>(context), std::move(size), renderbuffer, type)) { assert(!size.isEmpty()); } diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp index 9446fabecf..f4459556b8 100644 --- a/src/mbgl/util/offscreen_texture.hpp +++ b/src/mbgl/util/offscreen_texture.hpp @@ -6,20 +6,17 @@ namespace mbgl { -namespace gl { -class Context; -} // namespace gl - namespace gfx { +class Context; class Texture; } // namespace gfx class OffscreenTexture { public: - OffscreenTexture(gl::Context&, + OffscreenTexture(gfx::Context&, Size size = { 256, 256 }, gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte); - OffscreenTexture(gl::Context&, + OffscreenTexture(gfx::Context&, Size size, gl::Renderbuffer<gl::RenderbufferType::DepthComponent>&, gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte); diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index aad85f8d57..11920d1624 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -1,11 +1,11 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/stub_file_source.hpp> +#include <mbgl/test/map_adapter.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/annotation/annotation.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/image.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/util/io.hpp> #include <mbgl/util/run_loop.hpp> @@ -28,13 +28,11 @@ std::unique_ptr<style::Image> namedMarker(const std::string& name) { class AnnotationTest { public: util::RunLoop loop; - StubFileSource fileSource; ThreadPool threadPool { 4 }; - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool }; + HeadlessFrontend frontend { 1, threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, - threadPool, MapOptions().withMapMode(MapMode::Static)}; + MapAdapter map { frontend, MapObserver::nullObserver(), std::make_shared<StubFileSource>(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())}; void checkRendering(const char * name) { test::checkImage(std::string("test/fixtures/annotations/") + name, diff --git a/test/api/api_misuse.test.cpp b/test/api/api_misuse.test.cpp index 2ccfb0a7ff..cca47de69c 100644 --- a/test/api/api_misuse.test.cpp +++ b/test/api/api_misuse.test.cpp @@ -1,12 +1,11 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/stub_file_source.hpp> #include <mbgl/test/fixture_log_observer.hpp> +#include <mbgl/test/map_adapter.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/renderer/backend_scope.hpp> #include <mbgl/gl/headless_frontend.hpp> -#include <mbgl/storage/online_file_source.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/util/exception.hpp> #include <mbgl/util/run_loop.hpp> @@ -22,14 +21,12 @@ TEST(API, RenderWithoutCallback) { util::RunLoop loop; - StubFileSource fileSource; ThreadPool threadPool(4); - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool }; + HeadlessFrontend frontend { 1, threadPool }; - auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(), - pixelRatio, fileSource, threadPool, - MapOptions().withMapMode(MapMode::Static)); + auto map = std::make_unique<MapAdapter>(frontend, MapObserver::nullObserver(), + std::make_shared<StubFileSource>(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())); map->renderStill(nullptr); // Force Map thread to join. diff --git a/test/api/custom_geometry_source.test.cpp b/test/api/custom_geometry_source.test.cpp index 6959a36f15..f796e3086b 100644 --- a/test/api/custom_geometry_source.test.cpp +++ b/test/api/custom_geometry_source.test.cpp @@ -3,8 +3,8 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/util/shared_thread_pool.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/gl/headless_frontend.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/sources/custom_geometry_source.hpp> #include <mbgl/style/layers/fill_layer.hpp> @@ -20,12 +20,11 @@ using namespace mbgl::style; TEST(CustomGeometrySource, Grid) { util::RunLoop loop; - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); auto threadPool = sharedThreadPool(); - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, *threadPool }; - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, - *threadPool, MapOptions().withMapMode(MapMode::Static)); + HeadlessFrontend frontend { 1, *threadPool }; + Map map(frontend, MapObserver::nullObserver(), *threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()), + ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets")); map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); map.jumpTo(CameraOptions().withCenter(LatLng { 37.8, -122.5 }).withZoom(10.0)); diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp index 18c6dc1692..c836ab81ac 100644 --- a/test/api/custom_layer.test.cpp +++ b/test/api/custom_layer.test.cpp @@ -4,9 +4,9 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/util/default_thread_pool.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/gl/defines.hpp> #include <mbgl/gl/headless_frontend.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> @@ -90,12 +90,11 @@ public: TEST(CustomLayer, Basic) { util::RunLoop loop; - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); ThreadPool threadPool(4); - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool }; - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, - threadPool, MapOptions().withMapMode(MapMode::Static)); + HeadlessFrontend frontend { 1, threadPool }; + Map map(frontend, MapObserver::nullObserver(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()), + ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets")); map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); map.jumpTo(CameraOptions().withCenter(LatLng { 37.8, -122.5 }).withZoom(10.0)); map.getStyle().addLayer(std::make_unique<CustomLayer>( diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp index 5567eabc73..ddf5df6aab 100644 --- a/test/api/query.test.cpp +++ b/test/api/query.test.cpp @@ -1,4 +1,5 @@ -#include <mbgl/map/map.hpp> +#include <mbgl/test/map_adapter.hpp> + #include <mbgl/map/map_options.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/test/stub_file_source.hpp> @@ -33,16 +34,15 @@ public: } util::RunLoop loop; - StubFileSource fileSource; + std::shared_ptr<StubFileSource> fileSource = std::make_shared<StubFileSource>(); ThreadPool threadPool { 4 }; - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool }; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, - threadPool, MapOptions().withMapMode(MapMode::Static)}; + HeadlessFrontend frontend { 1, threadPool }; + MapAdapter map { frontend, MapObserver::nullObserver(), fileSource, threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())}; }; std::vector<Feature> getTopClusterFeature(QueryTest& test) { - test.fileSource.sourceResponse = [&] (const Resource& resource) { + test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("http://url"s, resource.url); Response response; response.data = std::make_unique<std::string>(util::read_file("test/fixtures/supercluster/places.json"s)); @@ -54,7 +54,7 @@ std::vector<Feature> getTopClusterFeature(QueryTest& test) { options.cluster = true; auto source = std::make_unique<GeoJSONSource>("cluster_source"s, options); source->setURL("http://url"s); - source->loadDescription(test.fileSource); + source->loadDescription(*test.fileSource); auto clusterLayer = std::make_unique<SymbolLayer>("cluster_layer"s, "cluster_source"s); clusterLayer->setIconImage("test-icon"s); diff --git a/test/api/recycle_map.cpp b/test/api/recycle_map.cpp index db576b4cf6..ac9de9b230 100644 --- a/test/api/recycle_map.cpp +++ b/test/api/recycle_map.cpp @@ -1,11 +1,10 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/stub_file_source.hpp> +#include <mbgl/test/map_adapter.hpp> #include <mbgl/gl/headless_frontend.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/renderer/backend_scope.hpp> -#include <mbgl/storage/online_file_source.hpp> #include <mbgl/style/layers/symbol_layer.hpp> #include <mbgl/style/sources/geojson_source.hpp> #include <mbgl/style/image.hpp> @@ -24,14 +23,12 @@ using namespace mbgl::style; TEST(API, RecycleMapUpdateImages) { util::RunLoop loop; - StubFileSource fileSource; ThreadPool threadPool(4); - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool }; - auto map = std::make_unique<Map>(frontend, MapObserver::nullObserver(), frontend.getSize(), - pixelRatio, fileSource, threadPool, - MapOptions().withMapMode(MapMode::Static)); + HeadlessFrontend frontend { 1, threadPool }; + auto map = std::make_unique<MapAdapter>(frontend, MapObserver::nullObserver(), + std::make_shared<StubFileSource>(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())); EXPECT_TRUE(map); diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index bc9f6aac5a..2be224382a 100644 --- a/test/gl/bucket.test.cpp +++ b/test/gl/bucket.test.cpp @@ -116,7 +116,7 @@ TEST(Buckets, SymbolBucket) { std::vector<SymbolInstance> symbolInstances; gl::Context context; - SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances) }; + SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), 1.0f }; ASSERT_FALSE(bucket.hasIconData()); ASSERT_FALSE(bucket.hasTextData()); ASSERT_FALSE(bucket.hasCollisionBoxData()); diff --git a/test/gl/context.test.cpp b/test/gl/context.test.cpp index 3c055c2ce0..291813bd9a 100644 --- a/test/gl/context.test.cpp +++ b/test/gl/context.test.cpp @@ -5,9 +5,9 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/util/default_thread_pool.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/gl/defines.hpp> #include <mbgl/gl/headless_frontend.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/style/style.hpp> #include <mbgl/style/layers/custom_layer.hpp> #include <mbgl/style/layers/fill_layer.hpp> @@ -86,14 +86,13 @@ struct Buffer { TEST(GLContextMode, Shared) { util::RunLoop loop; - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); ThreadPool threadPool(4); - float pixelRatio { 1 }; - HeadlessFrontend frontend { pixelRatio, threadPool, {}, GLContextMode::Shared }; + HeadlessFrontend frontend { 1, threadPool, {}, GLContextMode::Shared }; - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, - fileSource, threadPool, MapOptions().withMapMode(MapMode::Static)); + Map map(frontend, MapObserver::nullObserver(), threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()), + ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets")); map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); map.jumpTo(CameraOptions().withCenter(LatLng { 37.8, -122.5 }).withZoom(10.0)); diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 410a7e76af..be92890b07 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -3,12 +3,13 @@ #include <mbgl/test/stub_map_observer.hpp> #include <mbgl/test/fake_file_source.hpp> #include <mbgl/test/fixture_log_observer.hpp> +#include <mbgl/test/map_adapter.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/gl/headless_frontend.hpp> #include <mbgl/util/default_thread_pool.hpp> +#include <mbgl/storage/resource_options.hpp> #include <mbgl/storage/network_status.hpp> #include <mbgl/storage/default_file_source.hpp> #include <mbgl/storage/online_file_source.hpp> @@ -31,27 +32,26 @@ template <class FileSource = StubFileSource> class MapTest { public: util::RunLoop runLoop; - FileSource fileSource; + std::shared_ptr<FileSource> fileSource; ThreadPool threadPool { 4 }; StubMapObserver observer; HeadlessFrontend frontend; - Map map; + MapAdapter map; MapTest(float pixelRatio = 1, MapMode mode = MapMode::Static) - : frontend(pixelRatio, threadPool) - , map(frontend, observer, frontend.getSize(), pixelRatio, - fileSource, threadPool, MapOptions().withMapMode(mode)) { - } + : fileSource(std::make_shared<FileSource>()) + , frontend(pixelRatio, threadPool) + , map(frontend, observer, fileSource, threadPool, + MapOptions().withMapMode(mode).withSize(frontend.getSize()).withPixelRatio(pixelRatio)) {} template <typename T = FileSource> - MapTest(const std::string& cachePath, const std::string& assetRoot, + MapTest(const std::string& cachePath, const std::string& assetPath, float pixelRatio = 1, MapMode mode = MapMode::Static, typename std::enable_if<std::is_same<T, DefaultFileSource>::value>::type* = 0) - : fileSource { cachePath, assetRoot } + : fileSource(std::make_shared<T>(cachePath, assetPath)) , frontend(pixelRatio, threadPool) - , map(frontend, observer, frontend.getSize(), pixelRatio, - fileSource, threadPool, MapOptions().withMapMode(mode)) { - } + , map(frontend, observer, fileSource, threadPool, + MapOptions().withMapMode(mode).withSize(frontend.getSize()).withPixelRatio(pixelRatio)) {} }; TEST(Map, RendererState) { @@ -85,7 +85,7 @@ TEST(Map, RendererState) { const ScreenCoordinate& point = test.frontend.pixelForLatLng(coordinate); EXPECT_NEAR(coordinate.latitude(), latLng.latitude(), 1e-1); EXPECT_NEAR(coordinate.longitude(), latLng.longitude(), 1e-1); - const Size size = test.map.getSize(); + const Size size = test.map.getMapOptions().size(); EXPECT_NEAR(point.x, size.width / 2.0, 1e-7); EXPECT_NEAR(point.y, size.height / 2.0, 1e-7); } @@ -151,6 +151,18 @@ TEST(Map, LatLngBoundsToCamera) { EXPECT_NEAR(*virtualCamera.zoom, 1.55467, 1e-5); } +TEST(Map, LatLngBoundsToCameraWithExcessivePadding) { + MapTest<> test; + + test.map.jumpTo(CameraOptions().withCenter(LatLng { 40.712730, -74.005953 }).withZoom(16.0)); + + LatLngBounds bounds = LatLngBounds::hull({15.68169,73.499857}, {53.560711, 134.77281}); + + CameraOptions virtualCamera = test.map.cameraForLatLngBounds(bounds, {500, 0, 1200, 0}); + ASSERT_TRUE(bounds.contains(*virtualCamera.center)); + EXPECT_NEAR(*virtualCamera.zoom, 16.0, 1e-5); +} + TEST(Map, LatLngBoundsToCameraWithBearing) { MapTest<> test; @@ -209,9 +221,10 @@ TEST(Map, CameraToLatLngBounds) { test.map.jumpTo(CameraOptions().withCenter(LatLng { 45, 90 }).withZoom(16.0)); + const Size size = test.map.getMapOptions().size(); LatLngBounds bounds = LatLngBounds::hull( test.map.latLngForPixel({}), - test.map.latLngForPixel({ double(test.map.getSize().width), double(test.map.getSize().height) })); + test.map.latLngForPixel({ double(size.width), double(size.height) })); CameraOptions camera = test.map.getCameraOptions(); @@ -235,12 +248,12 @@ TEST(Map, Offline) { }; const std::string prefix = "http://127.0.0.1:3000/"; - test.fileSource.put(Resource::style(prefix + "style.json"), expiredItem("style.json")); - test.fileSource.put(Resource::source(prefix + "streets.json"), expiredItem("streets.json")); - test.fileSource.put(Resource::spriteJSON(prefix + "sprite", 1.0), expiredItem("sprite.json")); - test.fileSource.put(Resource::spriteImage(prefix + "sprite", 1.0), expiredItem("sprite.png")); - test.fileSource.put(Resource::tile(prefix + "{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), expiredItem("0-0-0.vector.pbf")); - test.fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf")); + test.fileSource->put(Resource::style(prefix + "style.json"), expiredItem("style.json")); + test.fileSource->put(Resource::source(prefix + "streets.json"), expiredItem("streets.json")); + test.fileSource->put(Resource::spriteJSON(prefix + "sprite", 1.0), expiredItem("sprite.json")); + test.fileSource->put(Resource::spriteImage(prefix + "sprite", 1.0), expiredItem("sprite.png")); + test.fileSource->put(Resource::tile(prefix + "{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), expiredItem("0-0-0.vector.pbf")); + test.fileSource->put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf")); NetworkStatus::Set(NetworkStatus::Status::Offline); test.map.getStyle().loadURL(prefix + "style.json"); @@ -308,6 +321,39 @@ TEST(Map, DefaultBoundOptions) { EXPECT_EQ(*bounds.bounds, LatLngBounds::unbounded()); } +TEST(Map, MapOptions) { + float pixelRatio { 2 }; + MapTest<> test { pixelRatio, MapMode::Continuous }; + + test.map.setNorthOrientation(NorthOrientation::Rightwards); + test.map.setConstrainMode(ConstrainMode::None); + test.map.setViewportMode(ViewportMode::FlippedY); + Size size = { 512, 512 }; + test.map.setSize(size); + + auto options = test.map.getMapOptions(); + EXPECT_EQ(options.mapMode(), MapMode::Continuous); + EXPECT_EQ(options.viewportMode(), ViewportMode::FlippedY); + EXPECT_EQ(options.constrainMode(), ConstrainMode::None); + EXPECT_EQ(options.northOrientation(), NorthOrientation::Rightwards); + EXPECT_EQ(options.size(), size); + EXPECT_EQ(options.pixelRatio(), pixelRatio); +} + +TEST(Map, DefaultMapOptions) { + MapTest<> test; + + auto options = test.map.getMapOptions(); + EXPECT_EQ(options.mapMode(), MapMode::Static); + EXPECT_EQ(options.viewportMode(), ViewportMode::Default); + EXPECT_EQ(options.constrainMode(), ConstrainMode::HeightOnly); + EXPECT_EQ(options.northOrientation(), NorthOrientation::Upwards); + EXPECT_TRUE(options.crossSourceCollisions()); + EXPECT_EQ(options.size().width, 256); + EXPECT_EQ(options.size().height, 256); + EXPECT_EQ(options.pixelRatio(), 1); +} + TEST(Map, SetStyleInvalidJSON) { Log::setObserver(std::make_unique<FixtureLogObserver>()); @@ -334,7 +380,7 @@ TEST(Map, SetStyleInvalidJSON) { TEST(Map, SetStyleInvalidURL) { MapTest<> test; - test.fileSource.styleResponse = [] (const Resource&) { + test.fileSource->styleResponse = [] (const Resource&) { Response response; response.error = std::make_unique<Response::Error>( Response::Error::Reason::Other, @@ -364,14 +410,14 @@ TEST(Map, StyleFresh) { MapTest<FakeFileSource> test; test.map.getStyle().loadURL("mapbox://styles/test"); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json")); response.expires = Timestamp::max(); - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); } TEST(Map, StyleExpired) { @@ -382,31 +428,31 @@ TEST(Map, StyleExpired) { MapTest<FakeFileSource> test; test.map.getStyle().loadURL("mapbox://styles/test"); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json")); response.expires = util::now() - 1h; - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); // Mutate layer. From now on, sending a response to the style won't overwrite it anymore, but // we should continue to wait for a fresh response. test.map.getStyle().addLayer(std::make_unique<style::BackgroundLayer>("bg")); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); // Send another expired response, and confirm that we didn't overwrite the style, but continue // to wait for a fresh response. - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); EXPECT_NE(nullptr, test.map.getStyle().getLayer("bg")); // Send a fresh response, and confirm that we didn't overwrite the style, but continue to wait // for a fresh response. response.expires = util::now() + 1h; - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); EXPECT_NE(nullptr, test.map.getStyle().getLayer("bg")); } @@ -418,20 +464,20 @@ TEST(Map, StyleExpiredWithAnnotations) { MapTest<FakeFileSource> test; test.map.getStyle().loadURL("mapbox://styles/test"); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json")); response.expires = util::now() - 1h; - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); test.map.addAnnotation(LineAnnotation { LineString<double> {{ { 0, 0 }, { 10, 10 } }} }); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); } TEST(Map, StyleExpiredWithRender) { @@ -442,20 +488,20 @@ TEST(Map, StyleExpiredWithRender) { MapTest<FakeFileSource> test; test.map.getStyle().loadURL("mapbox://styles/test"); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/empty.json")); response.expires = util::now() - 1h; - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); test.frontend.render(test.map); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); - test.fileSource.respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + test.fileSource->respond(Resource::Style, response); + EXPECT_EQ(1u, test.fileSource->requests.size()); } TEST(Map, StyleEarlyMutation) { @@ -468,9 +514,9 @@ TEST(Map, StyleEarlyMutation) { Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/api/water.json")); - test.fileSource.respond(Resource::Style, response); + test.fileSource->respond(Resource::Style, response); - EXPECT_EQ(1u, test.fileSource.requests.size()); + EXPECT_EQ(1u, test.fileSource->requests.size()); EXPECT_NE(nullptr, test.map.getStyle().getLayer("water")); } @@ -592,7 +638,7 @@ TEST(Map, DisabledSources) { MapTest<> test; // Always load the same image tile for raster layers. - test.fileSource.response = [] (const Resource& res) -> optional<Response> { + test.fileSource->response = [] (const Resource& res) -> optional<Response> { if (res.url == "asset://tile.png") { Response response; response.data = std::make_shared<std::string>( @@ -668,7 +714,7 @@ TEST(Map, DontLoadUnneededTiles) { using Tiles = std::unordered_set<std::string>; Tiles tiles; - test.fileSource.tileResponse = [&](const Resource& rsc) { + test.fileSource->tileResponse = [&](const Resource& rsc) { tiles.emplace(rsc.url); Response res; res.noContent = true; @@ -698,8 +744,6 @@ TEST(Map, DontLoadUnneededTiles) { TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) { util::RunLoop runLoop; ThreadPool threadPool { 4 }; - DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets"); - float pixelRatio { 1 }; using namespace std::chrono_literals; @@ -711,7 +755,7 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) { util::Timer timer; - HeadlessFrontend frontend(pixelRatio, threadPool); + HeadlessFrontend frontend(1, threadPool); StubMapObserver observer; observer.didFinishRenderingFrameCallback = [&] (MapObserver::RenderMode) { @@ -723,8 +767,9 @@ TEST(Map, TEST_DISABLED_ON_CI(ContinuousRendering)) { }); }; - Map map(frontend, observer, frontend.getSize(), pixelRatio, fileSource, - threadPool, MapOptions().withMapMode(MapMode::Continuous)); + Map map(frontend, observer, threadPool, + MapOptions().withMapMode(MapMode::Continuous).withSize(frontend.getSize()), + ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets")); map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); runLoop.run(); @@ -739,7 +784,7 @@ TEST(Map, NoContentTiles) { Response response; response.noContent = true; response.expires = util::now() + 1h; - test.fileSource.put(Resource::tile("http://example.com/{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, + test.fileSource->put(Resource::tile("http://example.com/{z}-{x}-{y}.vector.pbf", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); @@ -776,7 +821,7 @@ TEST(Map, NoContentTiles) { TEST(Map, Issue12432) { MapTest<> test { 1, MapMode::Continuous }; - test.fileSource.tileResponse = [&](const Resource&) { + test.fileSource->tileResponse = [&](const Resource&) { Response result; result.data = std::make_shared<std::string>(util::read_file("test/fixtures/map/issue12432/0-0-0.mvt")); return result; diff --git a/test/map/prefetch.test.cpp b/test/map/prefetch.test.cpp index dfde3a779b..3232c99a22 100644 --- a/test/map/prefetch.test.cpp +++ b/test/map/prefetch.test.cpp @@ -1,11 +1,10 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/stub_file_source.hpp> #include <mbgl/test/stub_map_observer.hpp> +#include <mbgl/test/map_adapter.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/gl/headless_frontend.hpp> -#include <mbgl/storage/default_file_source.hpp> #include <mbgl/style/style.hpp> #include <mbgl/util/default_thread_pool.hpp> #include <mbgl/util/image.hpp> @@ -24,7 +23,7 @@ using namespace std::chrono_literals; TEST(Map, PrefetchTiles) { util::RunLoop runLoop; ThreadPool threadPool(4); - StubFileSource fileSource; + std::shared_ptr<StubFileSource> fileSource = std::make_shared<StubFileSource>(); util::Timer emergencyShutoff; emergencyShutoff.start(10s, 0s, [&] { @@ -38,12 +37,12 @@ TEST(Map, PrefetchTiles) { }; HeadlessFrontend frontend { { 512, 512 }, 1, threadPool }; - Map map(frontend, observer, frontend.getSize(), 1, fileSource, threadPool, - MapOptions().withMapMode(MapMode::Continuous)); + MapAdapter map(frontend, observer, fileSource, threadPool, + MapOptions().withMapMode(MapMode::Continuous).withSize(frontend.getSize())); std::vector<int> tiles; - fileSource.response = [&] (const Resource& res) -> optional<Response> { + fileSource->response = [&] (const Resource& res) -> optional<Response> { static std::string tile = util::read_file("test/fixtures/map/prefetch/tile.png"); auto zoom = std::stoi(res.url); diff --git a/test/programs/symbol_program.test.cpp b/test/programs/symbol_program.test.cpp index 4d30e5dc3d..28d734c21a 100644 --- a/test/programs/symbol_program.test.cpp +++ b/test/programs/symbol_program.test.cpp @@ -9,9 +9,9 @@ using namespace mbgl::style::expression::dsl; TEST(SymbolProgram, SymbolSizeBinder) { auto binder = SymbolSizeBinder::create(5.0f, 12.0f, 0.0f); auto uniformValues = binder->uniformValues(5.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_size>(), 12.0f); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::size>(), 12.0f); binder = SymbolSizeBinder::create(1.0f, style::PropertyExpression<float>( interpolate( @@ -20,9 +20,9 @@ TEST(SymbolProgram, SymbolSizeBinder) { 0., literal(8.), 10., literal(18.))), 0.0f); uniformValues = binder->uniformValues(1.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), false); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_size>(), 9.5f); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::size>(), 9.5f); binder = SymbolSizeBinder::create(0.0f, style::PropertyExpression<float>( interpolate( @@ -31,9 +31,9 @@ TEST(SymbolProgram, SymbolSizeBinder) { 1., literal(8.), 11., literal(18.))), 0.0f); uniformValues = binder->uniformValues(0.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), false); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_size>(), 8.0f); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::size>(), 8.0f); binder = SymbolSizeBinder::create(12.0f, style::PropertyExpression<float>( interpolate( @@ -42,9 +42,9 @@ TEST(SymbolProgram, SymbolSizeBinder) { 1., literal(8.), 11., literal(18.))), 0.0f); uniformValues = binder->uniformValues(12.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), false); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_size>(), 18.0f); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::size>(), 18.0f); binder = SymbolSizeBinder::create(0.0f, style::PropertyExpression<float>( interpolate( @@ -53,8 +53,8 @@ TEST(SymbolProgram, SymbolSizeBinder) { 1., literal(8.), 11., literal(18.))), 0.0f); uniformValues = binder->uniformValues(12.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), true); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), true); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), false); binder = SymbolSizeBinder::create(5.0f, style::PropertyExpression<float>( interpolate( @@ -63,7 +63,7 @@ TEST(SymbolProgram, SymbolSizeBinder) { 1., interpolate(linear(), number(get("x")), 0., literal(8.), 100., literal(18.)), 11., interpolate(linear(), number(get("x")), 0., literal(12.), 100., literal(24.9)))), 0.0f); uniformValues = binder->uniformValues(5.5f); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_zoom_constant>(), false); - EXPECT_EQ(uniformValues.get<uniforms::u_is_size_feature_constant>(), false); - EXPECT_EQ(uniformValues.get<uniforms::u_size_t>(), 0.45f); + EXPECT_EQ(uniformValues.get<uniforms::is_size_zoom_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::is_size_feature_constant>(), false); + EXPECT_EQ(uniformValues.get<uniforms::size_t>(), 0.45f); } diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index 4a838d0f9c..b73d9b5c7a 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -1,9 +1,9 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/fixture_log_observer.hpp> -#include <mbgl/test/stub_file_source.hpp> #include <mbgl/test/stub_style_observer.hpp> #include <mbgl/renderer/image_manager.hpp> +#include <mbgl/renderer/image_manager_observer.hpp> #include <mbgl/sprite/sprite_parser.hpp> #include <mbgl/style/image_impl.hpp> #include <mbgl/util/io.hpp> @@ -108,11 +108,11 @@ TEST(ImageManager, RemoveReleasesBinPackRect) { class StubImageRequestor : public ImageRequestor { public: - void onImagesAvailable(ImageMap icons, ImageMap patterns, uint64_t imageCorrelationID_) final { - if (imagesAvailable && imageCorrelationID == imageCorrelationID_) imagesAvailable(icons, patterns); + void onImagesAvailable(ImageMap icons, ImageMap patterns, std::unordered_map<std::string, uint32_t> versionMap, uint64_t imageCorrelationID_) final { + if (imagesAvailable && imageCorrelationID == imageCorrelationID_) imagesAvailable(icons, patterns, versionMap); } - std::function<void (ImageMap, ImageMap)> imagesAvailable; + std::function<void (ImageMap, ImageMap, std::unordered_map<std::string, uint32_t>)> imagesAvailable; uint64_t imageCorrelationID = 0; }; @@ -121,7 +121,10 @@ TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) { StubImageRequestor requestor; bool notified = false; - requestor.imagesAvailable = [&] (ImageMap, ImageMap) { + ImageManagerObserver observer; + imageManager.setObserver(&observer); + + requestor.imagesAvailable = [&] (ImageMap, ImageMap, std::unordered_map<std::string, uint32_t>) { notified = true; }; @@ -132,6 +135,8 @@ TEST(ImageManager, NotifiesRequestorWhenSpriteIsLoaded) { ASSERT_FALSE(notified); imageManager.setLoaded(true); + ASSERT_FALSE(notified); + imageManager.notifyIfMissingImageAdded(); ASSERT_TRUE(notified); } @@ -140,7 +145,7 @@ TEST(ImageManager, NotifiesRequestorImmediatelyIfDependenciesAreSatisfied) { StubImageRequestor requestor; bool notified = false; - requestor.imagesAvailable = [&] (ImageMap, ImageMap) { + requestor.imagesAvailable = [&] (ImageMap, ImageMap, std::unordered_map<std::string, uint32_t>) { notified = true; }; diff --git a/test/src/mbgl/test/map_adapter.hpp b/test/src/mbgl/test/map_adapter.hpp new file mode 100644 index 0000000000..5bdab1d164 --- /dev/null +++ b/test/src/mbgl/test/map_adapter.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <mbgl/map/map.hpp> +#include <mbgl/map/map_impl.hpp> + +namespace mbgl { + +class FileSource; + +// Non-public version of mbgl::Map that accepts a file source as parameter. +class MapAdapter : public Map { +public: + explicit MapAdapter(RendererFrontend& frontend, + MapObserver& observer, + std::shared_ptr<FileSource> fileSource, + Scheduler& scheduler, + const MapOptions& options) + : Map(std::make_unique<Map::Impl>(frontend, observer, scheduler, std::move(fileSource), options)) {} +}; + +} // namespace mbgl diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp index e58a5fe5d0..7598d888e9 100644 --- a/test/style/style_layer.test.cpp +++ b/test/style/style_layer.test.cpp @@ -1,4 +1,5 @@ #include <mbgl/style/expression/dsl.hpp> +#include <mbgl/style/expression/match.hpp> #include <mbgl/style/expression/format_expression.hpp> #include <mbgl/style/style_impl.hpp> #include <mbgl/style/layers/background_layer.hpp> @@ -330,6 +331,17 @@ void testHasOverrides(LayoutType& layout) { PropertyExpression<Formatted> propExprOverride(std::move(formatExprOverride)); layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(propExprOverride)); EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get<TextField>())); + + // Nested expressions, overridden text-color. + auto formattedExpr1 = format("first paragraph"); + std::vector<FormatExpressionSection> sections{ { literal("second paragraph"), nullopt, nullopt, toColor(literal("blue")) } }; + auto formattedExpr2 = std::make_unique<FormatExpression>(std::move(sections)); + std::unordered_map<std::string, std::shared_ptr<Expression>> branches{ { "1st", std::move(formattedExpr1) }, + { "2nd", std::move(formattedExpr2) } }; + auto match = std::make_unique<Match<std::string>>(type::Formatted, literal("input"), std::move(branches), format("otherwise")); + PropertyExpression<Formatted> nestedPropExpr(std::move(match)); + layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(nestedPropExpr)); + EXPECT_TRUE(MockOverrides::hasOverrides(layout.template get<TextField>())); } } // namespace diff --git a/test/test-files.json b/test/test-files.json index 498237e072..58970689be 100644 --- a/test/test-files.json +++ b/test/test-files.json @@ -114,6 +114,7 @@ "mbgl/test/fake_file_source.hpp": "test/src/mbgl/test/fake_file_source.hpp", "mbgl/test/fixture_log_observer.hpp": "test/src/mbgl/test/fixture_log_observer.hpp", "mbgl/test/getrss.hpp": "test/src/mbgl/test/getrss.hpp", + "mbgl/test/map_adapter.hpp": "test/src/mbgl/test/map_adapter.hpp", "mbgl/test/mock.hpp": "test/src/mbgl/test/mock.hpp", "mbgl/test/sqlite3_test_fs.hpp": "test/src/mbgl/test/sqlite3_test_fs.hpp", "mbgl/test/stub_file_source.hpp": "test/src/mbgl/test/stub_file_source.hpp", diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index 67f82413b2..f121781766 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -7,11 +7,11 @@ using namespace mbgl; SymbolInstance makeSymbolInstance(float x, float y, std::u16string key) { GeometryCoordinates line; GlyphPositions positions; - const std::pair<Shaping, Shaping> shaping(Shaping{}, Shaping{}); + const ShapedTextOrientations shaping{}; style::SymbolLayoutProperties::Evaluated layout_; IndexedSubfeature subfeature(0, "", "", 0); Anchor anchor(x, y, 0, 0); - return {anchor, line, shaping, {}, layout_, 0, 0, 0, style::SymbolPlacementType::Point, {{0, 0}}, 0, 0, {{0, 0}}, positions, subfeature, 0, 0, key, 0, 0}; + return SymbolInstance(anchor, line, shaping, {}, layout_, 0, 0, 0, style::SymbolPlacementType::Point, {{0, 0}}, 0, 0, {{0, 0}}, positions, subfeature, 0, 0, key, 0, 0, 0.0f); } @@ -31,7 +31,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit")); mainInstances.push_back(makeSymbolInstance(2000, 2000, u"Toronto")); - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(mainID, mainBucket, maxCrossTileID); @@ -46,7 +46,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { childInstances.push_back(makeSymbolInstance(2000, 2000, u"Windsor")); childInstances.push_back(makeSymbolInstance(3000, 3000, u"Toronto")); childInstances.push_back(makeSymbolInstance(4001, 4001, u"Toronto")); - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f }; childBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(childID, childBucket, maxCrossTileID); @@ -62,7 +62,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { OverscaledTileID parentID(5, 0, 5, 4, 4); std::vector<SymbolInstance> parentInstances; parentInstances.push_back(makeSymbolInstance(500, 500, u"Detroit")); - SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances) }; + SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances), 1.0f }; parentBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(parentID, parentBucket, maxCrossTileID); @@ -78,7 +78,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { std::vector<SymbolInstance> grandchildInstances; grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Detroit")); grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Windsor")); - SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances) }; + SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances), 1.0f }; grandchildBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(grandchildID, grandchildBucket, maxCrossTileID); @@ -104,13 +104,13 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) { OverscaledTileID mainID(6, 0, 6, 8, 8); std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit")); - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; OverscaledTileID childID(7, 0, 7, 16, 16); std::vector<SymbolInstance> childInstances; childInstances.push_back(makeSymbolInstance(2000, 2000, u"Detroit")); - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f }; childBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns a new id @@ -145,7 +145,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) { std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; OverscaledTileID childID(7, 0, 7, 16, 16); @@ -153,7 +153,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) { childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // A' childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // B' childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // C' - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f }; childBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns new ids @@ -183,14 +183,14 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) { std::vector<SymbolInstance> firstInstances; firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B - SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances) }; + SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances), 1.0f }; firstBucket.bucketInstanceId = ++maxBucketInstanceId; std::vector<SymbolInstance> secondInstances; secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A' secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B' secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // C' - SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances) }; + SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances), 1.0f }; secondBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns new ids diff --git a/test/text/local_glyph_rasterizer.test.cpp b/test/text/local_glyph_rasterizer.test.cpp index d0fdb5ee57..26e4a2eb1d 100644 --- a/test/text/local_glyph_rasterizer.test.cpp +++ b/test/text/local_glyph_rasterizer.test.cpp @@ -1,6 +1,7 @@ #include <mbgl/test/util.hpp> #include <mbgl/test/stub_file_source.hpp> -#include <mbgl/map/map.hpp> +#include <mbgl/test/map_adapter.hpp> + #include <mbgl/map/map_options.hpp> #include <mbgl/util/io.hpp> #include <mbgl/util/run_loop.hpp> @@ -33,17 +34,16 @@ namespace { class LocalGlyphRasterizerTest { public: LocalGlyphRasterizerTest(const optional<std::string> fontFamily) - : frontend(pixelRatio, threadPool, optional<std::string>(), GLContextMode::Unique, fontFamily) + : frontend(1, threadPool, optional<std::string>(), GLContextMode::Unique, fontFamily) { } util::RunLoop loop; - StubFileSource fileSource; + std::shared_ptr<StubFileSource> fileSource = std::make_shared<StubFileSource>(); ThreadPool threadPool { 4 }; - float pixelRatio { 1 }; HeadlessFrontend frontend; - Map map { frontend, MapObserver::nullObserver(), frontend.getSize(), pixelRatio, fileSource, - threadPool, MapOptions().withMapMode(MapMode::Static)}; + MapAdapter map { frontend, MapObserver::nullObserver(), fileSource, threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())}; void checkRendering(const char * name) { test::checkImage(std::string("test/fixtures/local_glyphs/") + name, @@ -59,7 +59,7 @@ public: TEST(LocalGlyphRasterizer, PingFang) { LocalGlyphRasterizerTest test(std::string("PingFang")); - test.fileSource.glyphsResponse = [&] (const Resource& resource) { + test.fileSource->glyphsResponse = [&] (const Resource& resource) { EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/glyphs.pbf")); @@ -80,7 +80,7 @@ TEST(LocalGlyphRasterizer, NoLocal) { // the output should just contain basic latin characters. LocalGlyphRasterizerTest test({}); - test.fileSource.glyphsResponse = [&] (const Resource& resource) { + test.fileSource->glyphsResponse = [&] (const Resource& resource) { EXPECT_EQ(Resource::Kind::Glyphs, resource.kind); Response response; response.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/glyphs.pbf")); diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp index 36bed57ab5..e3ad976432 100644 --- a/test/util/memory.test.cpp +++ b/test/util/memory.test.cpp @@ -1,8 +1,8 @@ #include <mbgl/test/stub_file_source.hpp> #include <mbgl/test/getrss.hpp> #include <mbgl/test/util.hpp> +#include <mbgl/test/map_adapter.hpp> -#include <mbgl/map/map.hpp> #include <mbgl/map/map_options.hpp> #include <mbgl/gl/headless_frontend.hpp> #include <mbgl/util/default_thread_pool.hpp> @@ -16,6 +16,7 @@ #include <string> #include <unordered_map> #include <utility> +#include <memory> #include <cstdlib> #include <unistd.h> @@ -26,16 +27,16 @@ using namespace std::literals::string_literals; class MemoryTest { public: MemoryTest() { - fileSource.styleResponse = [&](const Resource& res) { return response("style_" + getType(res) + ".json");}; - fileSource.tileResponse = [&](const Resource& res) { return response(getType(res) + ".tile"); }; - fileSource.sourceResponse = [&](const Resource& res) { return response("source_" + getType(res) + ".json"); }; - fileSource.glyphsResponse = [&](const Resource&) { return response("glyphs.pbf"); }; - fileSource.spriteJSONResponse = [&](const Resource&) { return response("sprite.json"); }; - fileSource.spriteImageResponse = [&](const Resource&) { return response("sprite.png"); }; + fileSource->styleResponse = [&](const Resource& res) { return response("style_" + getType(res) + ".json");}; + fileSource->tileResponse = [&](const Resource& res) { return response(getType(res) + ".tile"); }; + fileSource->sourceResponse = [&](const Resource& res) { return response("source_" + getType(res) + ".json"); }; + fileSource->glyphsResponse = [&](const Resource&) { return response("glyphs.pbf"); }; + fileSource->spriteJSONResponse = [&](const Resource&) { return response("sprite.json"); }; + fileSource->spriteImageResponse = [&](const Resource&) { return response("sprite.png"); }; } util::RunLoop runLoop; - StubFileSource fileSource; + std::shared_ptr<StubFileSource> fileSource = std::make_shared<StubFileSource>(); ThreadPool threadPool { 4 }; private: @@ -72,8 +73,8 @@ TEST(Memory, Vector) { float ratio { 2 }; HeadlessFrontend frontend { { 256, 256 }, ratio, test.threadPool }; - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource, - test.threadPool, MapOptions().withMapMode(MapMode::Static)); + MapAdapter map(frontend, MapObserver::nullObserver(), test.fileSource, test.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(ratio)); map.jumpTo(CameraOptions().withZoom(16)); map.getStyle().loadURL("mapbox://streets"); @@ -85,8 +86,8 @@ TEST(Memory, Raster) { float ratio { 2 }; HeadlessFrontend frontend { { 256, 256 }, ratio, test.threadPool }; - Map map(frontend, MapObserver::nullObserver(), frontend.getSize(), ratio, test.fileSource, - test.threadPool, MapOptions().withMapMode(MapMode::Static)); + MapAdapter map(frontend, MapObserver::nullObserver(), test.fileSource, test.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(ratio)); map.getStyle().loadURL("mapbox://satellite"); frontend.render(map); @@ -123,15 +124,15 @@ TEST(Memory, Footprint) { public: FrontendAndMap(MemoryTest& test_, const char* style) : frontend(Size{ 256, 256 }, 2, test_.threadPool) - , map(frontend, MapObserver::nullObserver(), frontend.getSize(), 2, test_.fileSource - , test_.threadPool, MapOptions().withMapMode(MapMode::Static)) { + , map(frontend, MapObserver::nullObserver(), test_.fileSource, test_.threadPool, + MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()).withPixelRatio(2)) { map.jumpTo(CameraOptions().withZoom(16)); map.getStyle().loadURL(style); frontend.render(map); } HeadlessFrontend frontend; - Map map; + MapAdapter map; }; // Warm up buffers and cache. diff --git a/vendor/args b/vendor/args new file mode 160000 +Subproject f68b7e186cd2a020cbddfe3194c1d8ddfeeb101 diff --git a/vendor/args-files.json b/vendor/args-files.json new file mode 100644 index 0000000000..c3c9bb64c6 --- /dev/null +++ b/vendor/args-files.json @@ -0,0 +1,8 @@ +{ + "//": "This file is generated. Do not edit. Regenerate it with scripts/generate-file-lists.js", + "sources": [], + "public_headers": { + "args.hxx": "vendor/args/args.hxx" + }, + "private_headers": {} +} diff --git a/vendor/args.cmake b/vendor/args.cmake new file mode 100644 index 0000000000..b5839943c2 --- /dev/null +++ b/vendor/args.cmake @@ -0,0 +1,5 @@ +add_library(args INTERFACE) + +target_include_directories(args SYSTEM INTERFACE + ${CMAKE_SOURCE_DIR}/vendor/args +) diff --git a/vendor/optional.cmake b/vendor/optional.cmake index fa299da6a6..ed7bfe8a38 100644 --- a/vendor/optional.cmake +++ b/vendor/optional.cmake @@ -1,9 +1,5 @@ add_library(optional INTERFACE) -# This polyfill is needed for Windows and Android since these standard libraries don't ship with -# usable versions of <experimental/optional> -if(WIN32 OR MBGL_PLATFORM STREQUAL "android") - target_include_directories(optional SYSTEM INTERFACE - ${CMAKE_SOURCE_DIR}/vendor/optional/include - ) -endif() +target_include_directories(optional SYSTEM INTERFACE + ${CMAKE_SOURCE_DIR}/vendor/optional/include +) |