From 1ccaa1dc718c2b1d66014a9c3b0b8c725d4565f1 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Tue, 21 Mar 2017 12:54:29 -0400 Subject: [PATCH 01/33] [ios] podspec update to 3.5.0 (#8487) --- platform/ios/Mapbox-iOS-SDK-symbols.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index aa9a6cf7e..cc0fb07e2 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.0-rc.2' + version = '3.5.0' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 296015da1..987e9fed1 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.0-rc.2' + version = '3.5.0' m.name = 'Mapbox-iOS-SDK' m.version = version From 60717822e6a5f4b9262241cb4f4504d723b3a82b Mon Sep 17 00:00:00 2001 From: Anand Thakker Date: Wed, 22 Mar 2017 14:32:22 -0400 Subject: [PATCH 02/33] Use highp for color attributes (#8496) Addresses #8385 Updates shaders to reflect https://github.com/mapbox/mapbox-gl-js/pull/4476 --- mapbox-gl-js | 2 +- src/mbgl/shaders/circle.cpp | 12 ++++++------ src/mbgl/shaders/debug.cpp | 2 +- src/mbgl/shaders/fill.cpp | 6 +++--- src/mbgl/shaders/fill_outline.cpp | 6 +++--- src/mbgl/shaders/line.cpp | 6 +++--- src/mbgl/shaders/line_sdf.cpp | 6 +++--- src/mbgl/shaders/symbol_sdf.cpp | 12 ++++++------ 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 69bb05cef..dc426c212 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 69bb05cef27c99722f6616867032d64b5f12ee57 +Subproject commit dc426c212208bf06300b7412983c62c689e7a796 diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp index b479f1d40..1c977d2bc 100644 --- a/src/mbgl/shaders/circle.cpp +++ b/src/mbgl/shaders/circle.cpp @@ -14,8 +14,8 @@ uniform vec2 u_extrude_scale; attribute vec2 a_pos; uniform lowp float a_color_t; -attribute lowp vec4 a_color; -varying lowp vec4 color; +attribute highp vec4 a_color; +varying highp vec4 color; uniform lowp float a_radius_t; attribute mediump vec2 a_radius; varying mediump float radius; @@ -26,8 +26,8 @@ uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; uniform lowp float a_stroke_color_t; -attribute lowp vec4 a_stroke_color; -varying lowp vec4 stroke_color; +attribute highp vec4 a_stroke_color; +varying highp vec4 stroke_color; uniform lowp float a_stroke_width_t; attribute mediump vec2 a_stroke_width; varying mediump float stroke_width; @@ -69,11 +69,11 @@ void main(void) { )MBGL_SHADER"; const char* circle::fragmentSource = R"MBGL_SHADER( -varying lowp vec4 color; +varying highp vec4 color; varying mediump float radius; varying lowp float blur; varying lowp float opacity; -varying lowp vec4 stroke_color; +varying highp vec4 stroke_color; varying mediump float stroke_width; varying lowp float stroke_opacity; diff --git a/src/mbgl/shaders/debug.cpp b/src/mbgl/shaders/debug.cpp index 27a15698d..d39dcf25b 100644 --- a/src/mbgl/shaders/debug.cpp +++ b/src/mbgl/shaders/debug.cpp @@ -17,7 +17,7 @@ void main() { )MBGL_SHADER"; const char* debug::fragmentSource = R"MBGL_SHADER( -uniform lowp vec4 u_color; +uniform highp vec4 u_color; void main() { gl_FragColor = u_color; diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp index a1fba4d74..0b775273d 100644 --- a/src/mbgl/shaders/fill.cpp +++ b/src/mbgl/shaders/fill.cpp @@ -12,8 +12,8 @@ attribute vec2 a_pos; uniform mat4 u_matrix; uniform lowp float a_color_t; -attribute lowp vec4 a_color; -varying lowp vec4 color; +attribute highp vec4 a_color; +varying highp vec4 color; uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; @@ -27,7 +27,7 @@ void main() { )MBGL_SHADER"; const char* fill::fragmentSource = R"MBGL_SHADER( -varying lowp vec4 color; +varying highp vec4 color; varying lowp float opacity; void main() { diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp index 74201b518..3e160ac6c 100644 --- a/src/mbgl/shaders/fill_outline.cpp +++ b/src/mbgl/shaders/fill_outline.cpp @@ -15,8 +15,8 @@ uniform vec2 u_world; varying vec2 v_pos; uniform lowp float a_outline_color_t; -attribute lowp vec4 a_outline_color; -varying lowp vec4 outline_color; +attribute highp vec4 a_outline_color; +varying highp vec4 outline_color; uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; @@ -31,7 +31,7 @@ void main() { )MBGL_SHADER"; const char* fill_outline::fragmentSource = R"MBGL_SHADER( -varying lowp vec4 outline_color; +varying highp vec4 outline_color; varying lowp float opacity; varying vec2 v_pos; diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp index dc4aa774d..4392bd051 100644 --- a/src/mbgl/shaders/line.cpp +++ b/src/mbgl/shaders/line.cpp @@ -34,8 +34,8 @@ varying vec2 v_width2; varying float v_gamma_scale; uniform lowp float a_color_t; -attribute lowp vec4 a_color; -varying lowp vec4 color; +attribute highp vec4 a_color; +varying highp vec4 color; uniform lowp float a_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; @@ -105,7 +105,7 @@ void main() { )MBGL_SHADER"; const char* line::fragmentSource = R"MBGL_SHADER( -varying lowp vec4 color; +varying highp vec4 color; varying lowp float blur; varying lowp float opacity; diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp index cd0d4ac31..17a6a1973 100644 --- a/src/mbgl/shaders/line_sdf.cpp +++ b/src/mbgl/shaders/line_sdf.cpp @@ -42,8 +42,8 @@ varying vec2 v_tex_b; varying float v_gamma_scale; uniform lowp float a_color_t; -attribute lowp vec4 a_color; -varying lowp vec4 color; +attribute highp vec4 a_color; +varying highp vec4 color; uniform lowp float a_blur_t; attribute lowp vec2 a_blur; varying lowp float blur; @@ -127,7 +127,7 @@ varying vec2 v_tex_a; varying vec2 v_tex_b; varying float v_gamma_scale; -varying lowp vec4 color; +varying highp vec4 color; varying lowp float blur; varying lowp float opacity; diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index e0ee57b6d..7cbc9babf 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -14,11 +14,11 @@ attribute vec2 a_texture_pos; attribute vec4 a_data; uniform lowp float a_fill_color_t; -attribute lowp vec4 a_fill_color; -varying lowp vec4 fill_color; +attribute highp vec4 a_fill_color; +varying highp vec4 fill_color; uniform lowp float a_halo_color_t; -attribute lowp vec4 a_halo_color; -varying lowp vec4 halo_color; +attribute highp vec4 a_halo_color; +varying highp vec4 halo_color; uniform lowp float a_opacity_t; attribute lowp vec2 a_opacity; varying lowp float opacity; @@ -119,8 +119,8 @@ const char* symbol_sdf::fragmentSource = R"MBGL_SHADER( #define EDGE_GAMMA 0.105/DEVICE_PIXEL_RATIO uniform bool u_is_halo; -varying lowp vec4 fill_color; -varying lowp vec4 halo_color; +varying highp vec4 fill_color; +varying highp vec4 halo_color; varying lowp float opacity; varying lowp float halo_width; varying lowp float halo_blur; From 3a6d748bc4feb629271c6047afa0c4a3e364a751 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Wed, 22 Mar 2017 17:03:34 -0400 Subject: [PATCH 03/33] [android] [auto] Update properties to version 5.0.1 in preparation for build. --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- .../fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 7a6f777a3..9872478d9 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=5.1.0-SNAPSHOT +VERSION_NAME=5.0.1 POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native diff --git a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties index 1d436f129..bc0350fe1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties +++ b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties @@ -1,3 +1,3 @@ fabric-identifier=com.mapbox.mapboxsdk.mapbox-android-sdk -fabric-version=5.0.0 +fabric-version=5.0.1 fabric-build-type=binary From 81650240c420907493cfc656e401d1f027cfb873 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Thu, 23 Mar 2017 09:06:34 -0400 Subject: [PATCH 04/33] [android] update CHANGELOG.md with 5.0.1 information --- platform/android/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index d8338347c..5c6b8d57b 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 5.0.1 - March 22nd, 2017 + +5.0.1 is a patch release that addresses a shader precision issue that created a rendering problem on some devices. + +* Use `highp` for color attributes [#8385](https://github.com/mapbox/mapbox-gl-native/issues/8385) + ## 5.0.0 - March 17th, 2017 5.0.0 final release contains: From f169577aab74c9c4f23ed9d1c93b8a1fa605ce33 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Thu, 23 Mar 2017 09:07:51 -0400 Subject: [PATCH 05/33] [android] revert version name to snapshot --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 9872478d9..7a6f777a3 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=5.0.1 +VERSION_NAME=5.1.0-SNAPSHOT POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native From 348cffa1195e605d8012c2339a2b480727b59fba Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 9 Mar 2017 15:10:24 -0800 Subject: [PATCH 06/33] [core] Avoid -Wundefined-var-template warnings with clang 3.9+ --- include/mbgl/util/enum.hpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/mbgl/util/enum.hpp b/include/mbgl/util/enum.hpp index 48ffda463..369ca86bf 100644 --- a/include/mbgl/util/enum.hpp +++ b/include/mbgl/util/enum.hpp @@ -11,26 +11,26 @@ namespace mbgl { template class Enum { public: - using Value = std::pair; - - static const char * toString(T t) { - auto it = std::find_if(begin, end, [&] (const auto& v) { return t == v.first; }); - assert(it != end); return it->second; - } - - static optional toEnum(const std::string& s) { - auto it = std::find_if(begin, end, [&] (const auto& v) { return s == v.second; }); - return it == end ? optional() : it->first; - } - -private: - static const Value* begin; - static const Value* end; + static const char * toString(T); + static optional toEnum(const std::string&); }; -#define MBGL_DEFINE_ENUM(type, strings...) \ -const constexpr Enum::Value type##_names[] = strings; \ -template <> const Enum::Value* Enum::begin = std::begin(type##_names); \ -template <> const Enum::Value* Enum::end = std::end(type##_names) +#define MBGL_DEFINE_ENUM(T, values...) \ + \ +static const constexpr std::pair T##_names[] = values; \ + \ +template <> \ +const char * Enum::toString(T t) { \ + auto it = std::find_if(std::begin(T##_names), std::end(T##_names), \ + [&] (const auto& v) { return t == v.first; }); \ + assert(it != std::end(T##_names)); return it->second; \ +} \ + \ +template <> \ +optional Enum::toEnum(const std::string& s) { \ + auto it = std::find_if(std::begin(T##_names), std::end(T##_names), \ + [&] (const auto& v) { return s == v.second; }); \ + return it == std::end(T##_names) ? optional() : it->first; \ +} } // namespace mbgl From cfb26c0a7951e773ca3d01d692e988a2f060b244 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jan 2017 14:44:29 -0800 Subject: [PATCH 07/33] [test] Fix polygon construction to compile with clang 3.9.x --- test/api/annotations.test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index 30027d861..87d64d53d 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -73,7 +73,7 @@ TEST(Annotations, LineAnnotation) { TEST(Annotations, FillAnnotation) { AnnotationTest test; - Polygon polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + Polygon polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }; FillAnnotation annotation { polygon }; annotation.color = Color::red(); @@ -98,7 +98,7 @@ TEST(Annotations, AntimeridianAnnotationSmall) { lineAnnotation.width = { 2 }; test.map.addAnnotation(lineAnnotation); - Polygon polygon = {{ {{ { antimeridian+10, 0 }, { antimeridian - 10, 10 }, { antimeridian-10, -10 } }} }}; + Polygon polygon = { {{ { antimeridian+10, 0 }, { antimeridian - 10, 10 }, { antimeridian-10, -10 } }} }; FillAnnotation polygonAnnotation { polygon }; polygonAnnotation.color = Color::blue(); test.map.addAnnotation(polygonAnnotation); @@ -119,7 +119,7 @@ TEST(Annotations, AntimeridianAnnotationLarge) { lineAnnotation.width = { 2 }; test.map.addAnnotation(lineAnnotation); - Polygon polygon = {{ {{ { antimeridian-10, 0 }, { -antimeridian+10, 10 }, { -antimeridian+10, -10 } }} }}; + Polygon polygon = { {{ { antimeridian-10, 0 }, { -antimeridian+10, 10 }, { -antimeridian+10, -10 } }} }; FillAnnotation polygonAnnotation { polygon }; polygonAnnotation.color = Color::blue(); test.map.addAnnotation(polygonAnnotation); @@ -130,7 +130,7 @@ TEST(Annotations, AntimeridianAnnotationLarge) { TEST(Annotations, OverlappingFillAnnotation) { AnnotationTest test; - Polygon polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + Polygon polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }; FillAnnotation underlaidAnnotation { polygon }; underlaidAnnotation.color = Color::green(); FillAnnotation overlaidAnnotation { polygon }; @@ -145,7 +145,7 @@ TEST(Annotations, OverlappingFillAnnotation) { TEST(Annotations, StyleSourcedShapeAnnotation) { AnnotationTest test; - Polygon polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + Polygon polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }; test.map.setStyleJSON(util::read_file("test/fixtures/api/annotation.json")); test.map.addAnnotation(StyleSourcedAnnotation { polygon, "annotation" }); @@ -171,7 +171,7 @@ TEST(Annotations, NonImmediateAdd) { test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); test::render(test.map, test.view); - Polygon polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + Polygon polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }; FillAnnotation annotation { polygon }; annotation.color = Color::red(); @@ -245,7 +245,7 @@ TEST(Annotations, UpdateLineAnnotationStyle) { TEST(Annotations, UpdateFillAnnotationGeometry) { AnnotationTest test; - FillAnnotation annotation { Polygon {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }} }; + FillAnnotation annotation { Polygon { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} } }; annotation.color = Color::red(); test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); @@ -253,7 +253,7 @@ TEST(Annotations, UpdateFillAnnotationGeometry) { test::render(test.map, test.view); - annotation.geometry = Polygon {{ {{ { 0, 0 }, { 0, 45 }, { 45, 0 } }} }}; + annotation.geometry = Polygon { {{ { 0, 0 }, { 0, 45 }, { 45, 0 } }} }; test.map.updateAnnotation(fill, annotation); test.checkRendering("update_fill_geometry"); } @@ -261,7 +261,7 @@ TEST(Annotations, UpdateFillAnnotationGeometry) { TEST(Annotations, UpdateFillAnnotationStyle) { AnnotationTest test; - Polygon polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }}; + Polygon polygon = { {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }; FillAnnotation annotation { polygon }; annotation.color = Color::red(); From 8c34a5081c883eb7f4871b8e2c26f32b786ee8e4 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 8 Mar 2017 15:42:16 -0800 Subject: [PATCH 08/33] [linux, node] Build with clang 3.9 --- .travis.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 391520319..256e6a2aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,20 +5,20 @@ git: addons: apt: sources: - - &common_sources [ 'ubuntu-toolchain-r-test', 'george-edison55-precise-backports' ] + - &common_sources [ 'ubuntu-toolchain-r-test', 'george-edison55-precise-backports', 'llvm-toolchain-trusty-3.9' ] packages: - &common_packages [ 'libllvm3.8v4', 'cmake', 'cmake-data' ] - - &clang38_packages [ 'clang-3.8', 'libstdc++-5-dev', 'libstdc++6' ] + - &clang39_packages [ 'clang-3.9', 'libstdc++-5-dev', 'libstdc++6' ] - &gcc5_packages [ 'gcc-5', 'g++-5' ] - &glfw_packages [ 'libxrandr-dev', 'libxcursor-dev', 'libxinerama-dev' ] addons_shortcuts: - addons_clang38: &clang38 + addons_clang39: &clang39 apt: sources: *common_sources packages: - *common_packages - - *clang38_packages + - *clang39_packages - *glfw_packages addons_gcc5: &gcc5 apt: @@ -81,14 +81,14 @@ matrix: - git fetch origin master:refs/remotes/origin/master - make check - # EGL - Node - Clang 3.8 - Debug + # EGL - Node - Clang 3.9 - Debug - os: linux sudo: required dist: trusty language: node - compiler: "egl-node4-clang38-debug" - env: BUILDTYPE=Debug _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1 - addons: *clang38 + compiler: "egl-node4-clang39-debug" + env: BUILDTYPE=Debug _CXX=clang++-3.9 _CC=clang-3.9 WITH_EGL=1 + addons: *clang39 before_script: - mapbox_install_logbt - mapbox_start_xvfb @@ -104,14 +104,14 @@ matrix: after_failure: - aws s3 cp . s3://mapbox/mapbox-gl-native/render-tests/$TRAVIS_JOB_NUMBER --recursive --exclude "*" --include "*.trace" - # EGL - Node - Clang 3.8 - Release + # EGL - Node - Clang 3.9 - Release - os: linux sudo: required dist: trusty language: node - compiler: "egl-node4-clang38-release" - env: BUILDTYPE=Release _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1 - addons: *clang38 + compiler: "egl-node4-clang39-release" + env: BUILDTYPE=Release _CXX=clang++-3.9 _CC=clang-3.9 WITH_EGL=1 + addons: *clang39 before_script: # fglrx causes the GLX extension to be unavailable - sudo apt-get purge -qq fglrx @@ -148,14 +148,14 @@ matrix: - ccache --show-stats - ./platform/linux/scripts/coveralls.sh - # EGL - Clang 3.8 - Debug + # EGL - Clang 3.9 - Debug - os: linux sudo: required dist: trusty language: cpp - compiler: "egl-clang38-debug" - env: BUILDTYPE=Debug _CXX=clang++-3.8 _CC=clang-3.8 WITH_EGL=1 - addons: *clang38 + compiler: "egl-clang39-debug" + env: BUILDTYPE=Debug _CXX=clang++-3.9 _CC=clang-3.9 WITH_EGL=1 + addons: *clang39 before_script: - mapbox_start_xvfb - mapbox_export_mesa_library_path From c5c69102c5ca1aabb0efda1fe64224256a56bbb1 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Tue, 28 Mar 2017 16:06:16 -0400 Subject: [PATCH 09/33] [ios] nil check in visibleAnnotationsInRect to avoid crash (#8513) --- platform/ios/src/MGLMapView.mm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 1baebf60b..6ce41d6fb 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -3044,7 +3044,10 @@ public: continue; } MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); - [annotations addObject:annotationContext.annotation]; + if (annotationContext.annotation) + { + [annotations addObject:annotationContext.annotation]; + } } return [annotations copy]; From 1edbb0f24b3b405bfc203803fffb1fa1ed68f142 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 28 Mar 2017 16:02:48 -0700 Subject: [PATCH 10/33] [core] check null data in query source features (#8553) * [core] check null data in query source features * Include what you use --- src/mbgl/tile/geometry_tile.cpp | 5 +++++ test/tile/vector_tile.test.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 5f1fc5de6..5ccc037ce 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -165,6 +165,11 @@ void GeometryTile::queryRenderedFeatures( void GeometryTile::querySourceFeatures( std::vector& result, const style::SourceQueryOptions& options) { + + // Data not yet available + if (!data) { + return; + } // No source layers, specified, nothing to do if (!options.sourceLayers) { diff --git a/test/tile/vector_tile.test.cpp b/test/tile/vector_tile.test.cpp index 49fdcbd9f..f9bdafa5d 100644 --- a/test/tile/vector_tile.test.cpp +++ b/test/tile/vector_tile.test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -86,3 +87,12 @@ TEST(VectorTile, Issue7615) { EXPECT_EQ(symbolBucket.get(), tile.getBucket(symbolLayer)); } + +TEST(VectorTile, Issue8542) { + VectorTileTest test; + VectorTile tile(OverscaledTileID(0, 0, 0), "source", test.updateParameters, test.tileset); + + // Query before data is set + std::vector result; + tile.querySourceFeatures(result, { { {"layer"} }, {} }); +} From dcb14f98ee534b22cae8a0f829302a0b2b2459b2 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Mon, 27 Mar 2017 14:26:59 -0700 Subject: [PATCH 11/33] [ios] Modify return type so callout bridges with protocol in Swift `- (nullable UIView *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id )annotation;` bridges with a `UIView?` return type in Swift. This changes replaces the `UIView` type in the method signature so that, when bridged to Swift, the returned object is defined as `MGLCalloutView?`. --- platform/ios/CHANGELOG.md | 6 ++++++ platform/ios/src/MGLMapViewDelegate.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 40795a2ae..027689696 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,6 +2,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## 3.5.1 + +### Other changes + +* Fixed an issue that caused the return type of a map view delegate method to bridge incorrectly to applications written in Swift. ([#8541](https://github.com/mapbox/mapbox-gl-native/pull/8541)) + ## 3.5.0 ### Packaging diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h index c1faaa3d0..096711fcb 100644 --- a/platform/ios/src/MGLMapViewDelegate.h +++ b/platform/ios/src/MGLMapViewDelegate.h @@ -456,7 +456,7 @@ NS_ASSUME_NONNULL_BEGIN @return A view conforming to the `MGLCalloutView` protocol, or `nil` to use the default callout view. */ -- (nullable UIView *)mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id )annotation; +- (nullable id )mapView:(MGLMapView *)mapView calloutViewForAnnotation:(id )annotation; /** Returns the view to display on the left side of the standard callout bubble. From a46d91f7c5cbcdd9343d1a3dfba17e375a466e2a Mon Sep 17 00:00:00 2001 From: Tobrun Date: Thu, 30 Mar 2017 17:30:47 +0200 Subject: [PATCH 12/33] Revert 5.x touch changes (#8585) * Revert "[android] - only dispatch events if not handled by MarkerView (#8447)" This reverts commit 09d76854ab15b2a6f473c270da9d46e903e426da. * Revert "[android] - move touch handling of MarkerViews back to View#setOnClickListener. Workaround panning issue by dispatching touch events to the parent ViewGroup. (#8272)" This reverts commit 1693b389d7d17315b8a2a9bdd862207ace053f77. --- .../annotations/MarkerViewContainer.java | 34 ------------- .../annotations/MarkerViewManager.java | 49 +++++++++++-------- .../mapboxsdk/maps/AnnotationManager.java | 17 ++++--- .../mapbox/mapboxsdk/maps/IconManager.java | 21 ++++++++ .../res/layout/mapbox_mapview_internal.xml | 2 +- .../annotation/MarkerViewActivity.java | 7 --- 6 files changed, 60 insertions(+), 70 deletions(-) delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewContainer.java diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewContainer.java deleted file mode 100644 index d590582f0..000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewContainer.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.mapbox.mapboxsdk.annotations; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -/** - * ViewGroup that dispatches TouchEvents to the parent ViewGroup. - *

- * This allows to dispatch touch events that occur on MarkerView to MapView. - * https://github.com/mapbox/mapbox-gl-native/issues/5388 - *

- */ -public class MarkerViewContainer extends FrameLayout { - - public MarkerViewContainer(Context context, AttributeSet attrs) { - super(context, attrs); - setTag(false); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - super.dispatchTouchEvent(ev); - boolean actionUp = (boolean) getTag(); - if (!actionUp) { - ((ViewGroup) getParent()).onTouchEvent(ev); - } else { - setTag(false); - } - return true; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index 0f1298eea..315e12d28 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -8,7 +8,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.util.LongSparseArray; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -504,26 +503,6 @@ public class MarkerViewManager implements MapView.OnMapChangedListener { } } - adaptedView.setOnTouchListener(new View.OnTouchListener() { - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP) { - boolean clickHandled = false; - if (onMarkerViewClickListener != null) { - clickHandled = onMarkerViewClickListener.onMarkerClick(marker, v, adapter); - markerViewContainer.setTag(true); - } - - if (!clickHandled) { - ensureInfoWindowOffset(marker); - select(marker, v, adapter); - } - } - return true; - } - }); - marker.setMapboxMap(mapboxMap); markerViewMap.put(marker, adaptedView); if (convertView == null) { @@ -551,6 +530,34 @@ public class MarkerViewManager implements MapView.OnMapChangedListener { updateMarkerViewsPosition(); } + /** + * When the provided {@link MarkerView} is clicked on by a user, we check if a custom click + * event has been created and if not, display a {@link InfoWindow}. + * + * @param markerView that the click event occurred. + */ + public boolean onClickMarkerView(MarkerView markerView) { + boolean clickHandled = false; + + MapboxMap.MarkerViewAdapter adapter = getViewAdapter(markerView); + View view = getView(markerView); + if (adapter == null || view == null) { + // not a valid state + return true; + } + + if (onMarkerViewClickListener != null) { + clickHandled = onMarkerViewClickListener.onMarkerClick(markerView, view, adapter); + } + + if (!clickHandled) { + ensureInfoWindowOffset(markerView); + select(markerView, view, adapter); + } + + return clickHandled; + } + /** * Handles the {@link MarkerView}'s info window offset. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java index e91779dfd..0c7772335 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -10,7 +10,6 @@ import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; import com.mapbox.mapboxsdk.annotations.Icon; -import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerView; import com.mapbox.mapboxsdk.annotations.MarkerViewManager; @@ -257,11 +256,7 @@ class AnnotationManager { private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) { MarkerView marker = markerViewOptions.getMarker(); - Icon icon = markerViewOptions.getIcon(); - if (icon == null) { - icon = IconFactory.getInstance(mapView.getContext()).defaultMarkerView(); - } - marker.setIcon(icon); + iconManager.loadIconForMarkerView(marker); return marker; } @@ -665,16 +660,24 @@ class AnnotationManager { if (annotation.getId() == newSelectedMarkerId) { Marker marker = (Marker) annotation; - if (!(marker instanceof MarkerView)) { + if (marker instanceof MarkerView) { + handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker); + } else { if (onMarkerClickListener != null) { // end developer has provided a custom click listener handledDefaultClick = onMarkerClickListener.onMarkerClick(marker); } + } + + if (annotation instanceof MarkerView) { + markerViewManager.onClickMarkerView((MarkerView) annotation); + } else { if (!handledDefaultClick) { // only select marker if user didn't handle the click event themselves selectMarker(marker); } } + return true; } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java index c15263027..c9d81a88b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -71,6 +71,27 @@ class IconManager { return icon; } + Icon loadIconForMarkerView(MarkerView marker) { + Icon icon = marker.getIcon(); + int iconSize = icons.size() + 1; + if (icon == null) { + icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView(); + marker.setIcon(icon); + } + Bitmap bitmap = icon.getBitmap(); + averageIconHeight = averageIconHeight + (bitmap.getHeight() - averageIconHeight) / iconSize; + averageIconWidth = averageIconWidth + (bitmap.getWidth() - averageIconWidth) / iconSize; + if (!icons.contains(icon)) { + icons.add(icon); + } else { + Icon oldIcon = icons.get(icons.indexOf(icon)); + if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) { + throw new IconBitmapChangedException(); + } + } + return icon; + } + int getTopOffsetPixelsForIcon(Icon icon) { return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio()); } 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 7a38437fe..e6a267778 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 @@ -8,7 +8,7 @@ android:contentDescription="@null" android:visibility="gone"/> - Date: Fri, 31 Mar 2017 13:48:47 +0200 Subject: [PATCH 13/33] Cherry pick v5.0.2 changes (#8586) * [android] execute resource transform callback on the right thread * [android] allow resetting of resource transform callback * update CHANGELOG for v5.0.2 * [android] - correct anchoring when Icon is updated (#8519) --- platform/android/CHANGELOG.md | 8 ++++++++ .../com/mapbox/mapboxsdk/annotations/MarkerView.java | 9 +++++++++ .../mapbox/mapboxsdk/annotations/MarkerViewManager.java | 1 + .../java/com/mapbox/mapboxsdk/storage/FileSource.java | 4 ++-- platform/android/src/file_source.cpp | 6 +++--- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 5c6b8d57b..01d7b1ab5 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,14 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 5.0.2 - April 3, 2017 + +5.0.2 is a patch release that contains the following changes: + +* Fix resource transform callback [#8582](https://github.com/mapbox/mapbox-gl-native/pull/8582) +* Restore onTouch behaviour to 4.x version [#8585](https://github.com/mapbox/mapbox-gl-native/pull/8585) +* Restore anchoring after updating MarkerView Icon [#8519](https://github.com/mapbox/mapbox-gl-native/pull/8519) + ## 5.0.1 - March 22nd, 2017 5.0.1 is a patch release that addresses a shader precision issue that created a rendering problem on some devices. diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java index 220d3322c..30336d4eb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java @@ -389,6 +389,15 @@ public class MarkerView extends Marker { } } + /** + * Invalidates the MarkerView resulting in remeasuring the View. + */ + void invalidate() { + width = height = 0; + offsetX = offsetY = MapboxConstants.UNMEASURED; + markerViewManager.invalidateViewMarkersInVisibleRegion(); + } + /** * Get the String representation of a MarkerView. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index 315e12d28..bb51f3bfc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -232,6 +232,7 @@ public class MarkerViewManager implements MapView.OnMapChangedListener { View convertView = markerViewMap.get(markerView); if (convertView != null && convertView instanceof ImageView) { ((ImageView) convertView).setImageBitmap(markerView.getIcon().getBitmap()); + markerView.invalidate(); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index 868177702..a12d8f995 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -123,9 +123,9 @@ public class FileSource { * The callback will be executed on the main thread once for every requested URL. *

* - * @param callback the callback to be invoked + * @param callback the callback to be invoked or null to reset */ - public native void setResourceTransform(@NonNull final ResourceTransformCallback callback); + public native void setResourceTransform(final ResourceTransformCallback callback); private native void initialize(String accessToken, String cachePath, String apkPath); diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 30e1ff50f..20715bf92 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -46,10 +46,10 @@ void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()), - env + callback = std::shared_ptr(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()) ](mbgl::Resource::Kind kind, std::string&& url_) { - return FileSource::ResourceTransformCallback::onURL(const_cast(env), jni::Object(*callback), int(kind), url_); + android::UniqueEnv _env = android::AttachEnv(); + return FileSource::ResourceTransformCallback::onURL(*_env, jni::Object(*callback), int(kind), url_); }); } else { // Reset the callback From aa3db60300eecc52b21e4b38c70bd89566daa95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 26 Mar 2017 01:21:12 -0700 Subject: [PATCH 14/33] [ios, macos] Copyedited data-driven styling guides Cursorily copy-edited the data-driven styling guide, removing a stray class reference, replacing a redundant h1, and making stops examples platform-agnostic and less redundant. Fixed an issue in the style authors guide where style function tables appeared under each style layer type table. --- .../docs/guides/Data-Driven Styling.md.ejs | 59 ++++--- .../docs/guides/For Style Authors.md.ejs | 62 ++++--- .../ios/docs/guides/Data-Driven Styling.md | 59 ++++--- platform/ios/docs/guides/For Style Authors.md | 158 ++++-------------- .../macos/docs/guides/Data-Driven Styling.md | 59 ++++--- .../macos/docs/guides/For Style Authors.md | 158 ++++-------------- 6 files changed, 198 insertions(+), 357 deletions(-) diff --git a/platform/darwin/docs/guides/Data-Driven Styling.md.ejs b/platform/darwin/docs/guides/Data-Driven Styling.md.ejs index 820f71f59..7b597c673 100644 --- a/platform/darwin/docs/guides/Data-Driven Styling.md.ejs +++ b/platform/darwin/docs/guides/Data-Driven Styling.md.ejs @@ -12,44 +12,43 @@ # Data-Driven Styling -Mapbox’s data-driven styling features allow you to use data properties to style your maps. You can style map features automatically based on their individual attributes. +Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -# How to use Data-Driven Styling This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -`MGLStyleFunction` +## Style functions There are three subclasses of `MGLStyleFunction`: -* `MGLCameraStyleFunction` - For a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. -* `MGLSourceStyleFunction` - For a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. -* `MGLCompositeStyleFunction` - For a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. +* `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. +* `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. +* `MGLCompositeStyleFunction` is a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. -The documentation for individual style properties will note which style functions are enabled for that property. +The documentation for each individual style layer property notes which style functions are enabled for that property. ## Stops Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key. ```swift -let stops = [0: MGLStyleValue(rawValue: UIColor.yellow), - 2.5: MGLStyleValue(rawValue: UIColor.orange), - 5: MGLStyleValue(rawValue: UIColor.red), - 7.5: MGLStyleValue(rawValue: UIColor.blue), - 10: MGLStyleValue(rawValue: UIColor.white)] +let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] ``` -## Interpolation Mode +## Interpolation mode The effect a key has on the style value is determined by the interpolation mode. There are four interpolation modes that can be used with a source style function: exponential, interval, categorical, and identity. You can also use exponential and interval interpolation modes with a camera style function. ### Linear -`MGLInterpolationModelExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation, and doesn’t need to be included in the options dictionary. +`MGLInterpolationModeExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation and doesn’t need to be included in the options dictionary. The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value. @@ -61,11 +60,11 @@ let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbo let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) style.addSource(source) -let stops = [0: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.yellow), - 2.5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.orange), - 5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.red), - 7.5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.blue), - 10: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.white)] +let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] let layer = MGLCircleStyleLayer(identifier: "circles", source: source) layer.circleColor = MGLStyleValue(interpolationMode: .exponential, @@ -80,7 +79,7 @@ style.insertLayer(layer, below: symbolLayer) ### Exponential -`MGLInterpolationModelExponential` combined with any `MGLStyleFunctionOptionInterpolationBase` greater than `0`, you can interpolate between values exponentially, create an accelerated ramp effect. +By combining `MGLInterpolationModeExponential` with an `MGLStyleFunctionOptionInterpolationBase` greater than `0` (other than `1`), you can interpolate between values exponentially, create an accelerated ramp effect. Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. @@ -106,11 +105,11 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential, When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on. ``` swift -let stops = [0: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.yellow), - 2.5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.orange), - 5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.red), - 7.5: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.blue), - 10: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.white)] +let stops = [0: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] layer.circleColor = MGLStyleValue(interpolationMode: .interval, sourceStops: stops, @@ -122,19 +121,19 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, ### Categorical -Returns the output value that is equal to the stop for the function input. We’re going to use a different stops dictionary than we did for the previous two modes. +At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. ``` swift -let categoricalStops = ["earthquake": MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.orange), - "explosion": MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.red), - "quarry blast": MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.yellow)] +let categoricalStops = ["earthquake": MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .orange), + "explosion": MGLStyleValue(rawValue: .red), + "quarry blast": MGLStyleValue(rawValue: .yellow)] layer.circleColor = MGLStyleValue(interpolationMode: .categorical, sourceStops: categoricalStops, attributeName: "type", - options: [.defaultValue: MGLStyleValue(rawValue: <%- cocoaPrefix %>Color.blue)]) + options: [.defaultValue: MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .blue)]) ``` diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 92ce4c159..93ca7014a 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -240,30 +240,6 @@ whose names differ from the style specification are listed below: <% for (const type in renamedProperties) { -%> <% if (renamedProperties.hasOwnProperty(type)) { -%> -### <%- camelize(type) %> style functions - -The runtime styling API introduces `MGLStyleFunction` to the <%- os %> SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### <%- camelize(type) %> style layers In style JSON | In Objective-C | In Swift @@ -280,10 +256,12 @@ In style JSON | In Objective-C | In Swift Each property representing a layout or paint attribute is set to an `MGLStyleValue` object, which is either an `MGLConstantStyleValue` object (for -constant values) or an `MGLStyleFunction` object (for zoom level functions). The +constant values) or an `MGLStyleFunction` object (for style functions). The style value object is a container for the raw value or function parameters that you want the attribute to be set to. +### Constant style values + In contrast to the JSON type that the style specification defines for each layout or paint property, the style value object often contains a more specific Foundation or Cocoa type. General rules for attribute types are listed below. @@ -326,6 +304,40 @@ translation downward. This is the reverse of how `CGVector` is interpreted on iOS. <% } -%> +### Style functions + +A _style function_ allows you to vary the value of a layout or paint attribute +based on the zoom level, data provided by content sources, or both. For more +information about style functions that incorporate data from sources, see +“[Data-Driven Styling](data-driven-styling.html)”. + +Each kind of style function is represented by a distinct class, but you +typically create style functions as you create any other style value, using +class methods on `MGLStyleValue`: + +In style specification | SDK class | SDK factory method +---------------------------|-----------------------------|------------------- +zoom function | `MGLCameraStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]` +property function | `MGLSourceStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:sourceStops:attributeName:options:]` +zoom-and-property function | `MGLCompositeStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:compositeStops:attributeName:options:]` + +The documentation for each individual style layer property indicates the kinds +of style functions that are enabled for that property. + +When you create a style function, you specify an _interpolation mode_ and a +series of _stops_. Each stop determines the effective value displayed at a +particular zoom level (for camera functions) or the effective value on features +with a particular attribute value in the content source (for source functions). +The interpolation mode tells the SDK how to calculate the effective value +between any two stops: + +In style specification | In the SDK +-----------------------------|----------- +`exponential` | `MGLInterpolationModeExponential` +`interval` | `MGLInterpolationModeInterval` +`categorical` | `MGLInterpolationModeCategorical` +`identity` | `MGLInterpolationModeIdentity` + ## Filtering sources You can filter a shape or vector source by setting the diff --git a/platform/ios/docs/guides/Data-Driven Styling.md b/platform/ios/docs/guides/Data-Driven Styling.md index 0b685512b..a5ed874b5 100644 --- a/platform/ios/docs/guides/Data-Driven Styling.md +++ b/platform/ios/docs/guides/Data-Driven Styling.md @@ -6,44 +6,43 @@ # Data-Driven Styling -Mapbox’s data-driven styling features allow you to use data properties to style your maps. You can style map features automatically based on their individual attributes. +Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -# How to use Data-Driven Styling This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -`MGLStyleFunction` +## Style functions There are three subclasses of `MGLStyleFunction`: -* `MGLCameraStyleFunction` - For a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. -* `MGLSourceStyleFunction` - For a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. -* `MGLCompositeStyleFunction` - For a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. +* `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. +* `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. +* `MGLCompositeStyleFunction` is a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. -The documentation for individual style properties will note which style functions are enabled for that property. +The documentation for each individual style layer property notes which style functions are enabled for that property. ## Stops Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key. ```swift -let stops = [0: MGLStyleValue(rawValue: UIColor.yellow), - 2.5: MGLStyleValue(rawValue: UIColor.orange), - 5: MGLStyleValue(rawValue: UIColor.red), - 7.5: MGLStyleValue(rawValue: UIColor.blue), - 10: MGLStyleValue(rawValue: UIColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] ``` -## Interpolation Mode +## Interpolation mode The effect a key has on the style value is determined by the interpolation mode. There are four interpolation modes that can be used with a source style function: exponential, interval, categorical, and identity. You can also use exponential and interval interpolation modes with a camera style function. ### Linear -`MGLInterpolationModelExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation, and doesn’t need to be included in the options dictionary. +`MGLInterpolationModeExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation and doesn’t need to be included in the options dictionary. The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value. @@ -55,11 +54,11 @@ let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbo let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) style.addSource(source) -let stops = [0: MGLStyleValue(rawValue: UIColor.yellow), - 2.5: MGLStyleValue(rawValue: UIColor.orange), - 5: MGLStyleValue(rawValue: UIColor.red), - 7.5: MGLStyleValue(rawValue: UIColor.blue), - 10: MGLStyleValue(rawValue: UIColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] let layer = MGLCircleStyleLayer(identifier: "circles", source: source) layer.circleColor = MGLStyleValue(interpolationMode: .exponential, @@ -74,7 +73,7 @@ style.insertLayer(layer, below: symbolLayer) ### Exponential -`MGLInterpolationModelExponential` combined with any `MGLStyleFunctionOptionInterpolationBase` greater than `0`, you can interpolate between values exponentially, create an accelerated ramp effect. +By combining `MGLInterpolationModeExponential` with an `MGLStyleFunctionOptionInterpolationBase` greater than `0` (other than `1`), you can interpolate between values exponentially, create an accelerated ramp effect. Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. @@ -100,11 +99,11 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential, When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on. ``` swift -let stops = [0: MGLStyleValue(rawValue: UIColor.yellow), - 2.5: MGLStyleValue(rawValue: UIColor.orange), - 5: MGLStyleValue(rawValue: UIColor.red), - 7.5: MGLStyleValue(rawValue: UIColor.blue), - 10: MGLStyleValue(rawValue: UIColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] layer.circleColor = MGLStyleValue(interpolationMode: .interval, sourceStops: stops, @@ -116,19 +115,19 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, ### Categorical -Returns the output value that is equal to the stop for the function input. We’re going to use a different stops dictionary than we did for the previous two modes. +At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. ``` swift -let categoricalStops = ["earthquake": MGLStyleValue(rawValue: UIColor.orange), - "explosion": MGLStyleValue(rawValue: UIColor.red), - "quarry blast": MGLStyleValue(rawValue: UIColor.yellow)] +let categoricalStops = ["earthquake": MGLStyleValue(rawValue: .orange), + "explosion": MGLStyleValue(rawValue: .red), + "quarry blast": MGLStyleValue(rawValue: .yellow)] layer.circleColor = MGLStyleValue(interpolationMode: .categorical, sourceStops: categoricalStops, attributeName: "type", - options: [.defaultValue: MGLStyleValue(rawValue: UIColor.blue)]) + options: [.defaultValue: MGLStyleValue(rawValue: .blue)]) ``` diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 952be6bec..d3ba331e0 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -190,30 +190,6 @@ layer objects. The property names generally correspond to the style JSON properties, except for the use of camelCase instead of kebab-case. Properties whose names differ from the style specification are listed below: -### Circle style functions - -The runtime styling API introduces `MGLStyleFunction` to the iOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Circle style layers In style JSON | In Objective-C | In Swift @@ -222,30 +198,6 @@ In style JSON | In Objective-C | In Swift `circle-translate` | `MGLCircleStyleLayer.circleTranslation` | `MGLCircleStyleLayer.circleTranslation` `circle-translate-anchor` | `MGLCircleStyleLayer.circleTranslationAnchor` | `MGLCircleStyleLayer.circleTranslationAnchor` -### Fill style functions - -The runtime styling API introduces `MGLStyleFunction` to the iOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Fill style layers In style JSON | In Objective-C | In Swift @@ -254,30 +206,6 @@ In style JSON | In Objective-C | In Swift `fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation` `fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor` -### Line style functions - -The runtime styling API introduces `MGLStyleFunction` to the iOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Line style layers In style JSON | In Objective-C | In Swift @@ -286,30 +214,6 @@ In style JSON | In Objective-C | In Swift `line-translate` | `MGLLineStyleLayer.lineTranslation` | `MGLLineStyleLayer.lineTranslation` `line-translate-anchor` | `MGLLineStyleLayer.lineTranslationAnchor` | `MGLLineStyleLayer.lineTranslationAnchor` -### Raster style functions - -The runtime styling API introduces `MGLStyleFunction` to the iOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Raster style layers In style JSON | In Objective-C | In Swift @@ -318,30 +222,6 @@ In style JSON | In Objective-C | In Swift `raster-brightness-min` | `MGLRasterStyleLayer.minimumRasterBrightness` | `MGLRasterStyleLayer.minimumRasterBrightness` `raster-hue-rotate` | `MGLRasterStyleLayer.rasterHueRotation` | `MGLRasterStyleLayer.rasterHueRotation` -### Symbol style functions - -The runtime styling API introduces `MGLStyleFunction` to the iOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Symbol style layers In style JSON | In Objective-C | In Swift @@ -374,10 +254,12 @@ In style JSON | In Objective-C | In Swift Each property representing a layout or paint attribute is set to an `MGLStyleValue` object, which is either an `MGLConstantStyleValue` object (for -constant values) or an `MGLStyleFunction` object (for zoom level functions). The +constant values) or an `MGLStyleFunction` object (for style functions). The style value object is a container for the raw value or function parameters that you want the attribute to be set to. +### Constant style values + In contrast to the JSON type that the style specification defines for each layout or paint property, the style value object often contains a more specific Foundation or Cocoa type. General rules for attribute types are listed below. @@ -402,6 +284,40 @@ in Swift are specified in counterclockwise order, in contrast to the clockwise order defined by the style specification. +### Style functions + +A _style function_ allows you to vary the value of a layout or paint attribute +based on the zoom level, data provided by content sources, or both. For more +information about style functions that incorporate data from sources, see +“[Data-Driven Styling](data-driven-styling.html)”. + +Each kind of style function is represented by a distinct class, but you +typically create style functions as you create any other style value, using +class methods on `MGLStyleValue`: + +In style specification | SDK class | SDK factory method +---------------------------|-----------------------------|------------------- +zoom function | `MGLCameraStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]` +property function | `MGLSourceStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:sourceStops:attributeName:options:]` +zoom-and-property function | `MGLCompositeStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:compositeStops:attributeName:options:]` + +The documentation for each individual style layer property indicates the kinds +of style functions that are enabled for that property. + +When you create a style function, you specify an _interpolation mode_ and a +series of _stops_. Each stop determines the effective value displayed at a +particular zoom level (for camera functions) or the effective value on features +with a particular attribute value in the content source (for source functions). +The interpolation mode tells the SDK how to calculate the effective value +between any two stops: + +In style specification | In the SDK +-----------------------------|----------- +`exponential` | `MGLInterpolationModeExponential` +`interval` | `MGLInterpolationModeInterval` +`categorical` | `MGLInterpolationModeCategorical` +`identity` | `MGLInterpolationModeIdentity` + ## Filtering sources You can filter a shape or vector source by setting the diff --git a/platform/macos/docs/guides/Data-Driven Styling.md b/platform/macos/docs/guides/Data-Driven Styling.md index 9e38e7131..2adb0197d 100644 --- a/platform/macos/docs/guides/Data-Driven Styling.md +++ b/platform/macos/docs/guides/Data-Driven Styling.md @@ -6,44 +6,43 @@ # Data-Driven Styling -Mapbox’s data-driven styling features allow you to use data properties to style your maps. You can style map features automatically based on their individual attributes. +Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -# How to use Data-Driven Styling This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -`MGLStyleFunction` +## Style functions There are three subclasses of `MGLStyleFunction`: -* `MGLCameraStyleFunction` - For a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. -* `MGLSourceStyleFunction` - For a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. -* `MGLCompositeStyleFunction` - For a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. +* `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. +* `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. +* `MGLCompositeStyleFunction` is a style value that changes with both zoom level and attribute values. For example, you can add a circle layer where each circle has a radius based on both zoom level and the magnitude of an earthquake. -The documentation for individual style properties will note which style functions are enabled for that property. +The documentation for each individual style layer property notes which style functions are enabled for that property. ## Stops Stops are key-value pairs that that determine a style value. With a `MGLCameraSourceFunction` stop, you can use a dictionary with a zoom level for a key and a `MGLStyleValue` for the value. For example, you can use a stops dictionary with zoom levels 0, 10, and 20 as keys, and yellow, orange, and red as the values. A `MGLSourceStyleFunction` uses the relevant attribute value as the key. ```swift -let stops = [0: MGLStyleValue(rawValue: UIColor.yellow), - 2.5: MGLStyleValue(rawValue: UIColor.orange), - 5: MGLStyleValue(rawValue: UIColor.red), - 7.5: MGLStyleValue(rawValue: UIColor.blue), - 10: MGLStyleValue(rawValue: UIColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] ``` -## Interpolation Mode +## Interpolation mode The effect a key has on the style value is determined by the interpolation mode. There are four interpolation modes that can be used with a source style function: exponential, interval, categorical, and identity. You can also use exponential and interval interpolation modes with a camera style function. ### Linear -`MGLInterpolationModelExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation, and doesn’t need to be included in the options dictionary. +`MGLInterpolationModeExponential` interpolates linearly or exponentially between style function stop values. By default, the `MGLStyleFunction` options parameter `MGLStyleFunctionOptionInterpolationBase` equals `1`, which represents linear interpolation and doesn’t need to be included in the options dictionary. The stops dictionary below, for example, shows colors that continuously shift from yellow to orange to red to blue to white based on the attribute value. @@ -55,11 +54,11 @@ let symbolLayer = MGLSymbolStyleLayer(identifier: "place-city-sm", source: symbo let source = MGLShapeSource(identifier: "earthquakes", url: url, options: nil) style.addSource(source) -let stops = [0: MGLStyleValue(rawValue: NSColor.yellow), - 2.5: MGLStyleValue(rawValue: NSColor.orange), - 5: MGLStyleValue(rawValue: NSColor.red), - 7.5: MGLStyleValue(rawValue: NSColor.blue), - 10: MGLStyleValue(rawValue: NSColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] let layer = MGLCircleStyleLayer(identifier: "circles", source: source) layer.circleColor = MGLStyleValue(interpolationMode: .exponential, @@ -74,7 +73,7 @@ style.insertLayer(layer, below: symbolLayer) ### Exponential -`MGLInterpolationModelExponential` combined with any `MGLStyleFunctionOptionInterpolationBase` greater than `0`, you can interpolate between values exponentially, create an accelerated ramp effect. +By combining `MGLInterpolationModeExponential` with an `MGLStyleFunctionOptionInterpolationBase` greater than `0` (other than `1`), you can interpolate between values exponentially, create an accelerated ramp effect. Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. @@ -100,11 +99,11 @@ layer.circleRadius = MGLStyleValue(interpolationMode: .exponential, When we use the stops dictionary given above with an interval interpolation mode, we create ranges where earthquakes with a magnitude of 0 to just less than 2.5 would be yellow, 2.5 to just less than 5 would be orange, and so on. ``` swift -let stops = [0: MGLStyleValue(rawValue: NSColor.yellow), - 2.5: MGLStyleValue(rawValue: NSColor.orange), - 5: MGLStyleValue(rawValue: NSColor.red), - 7.5: MGLStyleValue(rawValue: NSColor.blue), - 10: MGLStyleValue(rawValue: NSColor.white)] +let stops = [0: MGLStyleValue(rawValue: .yellow), + 2.5: MGLStyleValue(rawValue: .orange), + 5: MGLStyleValue(rawValue: .red), + 7.5: MGLStyleValue(rawValue: .blue), + 10: MGLStyleValue(rawValue: .white)] layer.circleColor = MGLStyleValue(interpolationMode: .interval, sourceStops: stops, @@ -116,19 +115,19 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, ### Categorical -Returns the output value that is equal to the stop for the function input. We’re going to use a different stops dictionary than we did for the previous two modes. +At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. ``` swift -let categoricalStops = ["earthquake": MGLStyleValue(rawValue: NSColor.orange), - "explosion": MGLStyleValue(rawValue: NSColor.red), - "quarry blast": MGLStyleValue(rawValue: NSColor.yellow)] +let categoricalStops = ["earthquake": MGLStyleValue(rawValue: .orange), + "explosion": MGLStyleValue(rawValue: .red), + "quarry blast": MGLStyleValue(rawValue: .yellow)] layer.circleColor = MGLStyleValue(interpolationMode: .categorical, sourceStops: categoricalStops, attributeName: "type", - options: [.defaultValue: MGLStyleValue(rawValue: NSColor.blue)]) + options: [.defaultValue: MGLStyleValue(rawValue: .blue)]) ``` diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md index 9c3665d81..f57692185 100644 --- a/platform/macos/docs/guides/For Style Authors.md +++ b/platform/macos/docs/guides/For Style Authors.md @@ -179,30 +179,6 @@ layer objects. The property names generally correspond to the style JSON properties, except for the use of camelCase instead of kebab-case. Properties whose names differ from the style specification are listed below: -### Circle style functions - -The runtime styling API introduces `MGLStyleFunction` to the macOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Circle style layers In style JSON | In Objective-C | In Swift @@ -211,30 +187,6 @@ In style JSON | In Objective-C | In Swift `circle-translate` | `MGLCircleStyleLayer.circleTranslation` | `MGLCircleStyleLayer.circleTranslation` `circle-translate-anchor` | `MGLCircleStyleLayer.circleTranslationAnchor` | `MGLCircleStyleLayer.circleTranslationAnchor` -### Fill style functions - -The runtime styling API introduces `MGLStyleFunction` to the macOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Fill style layers In style JSON | In Objective-C | In Swift @@ -243,30 +195,6 @@ In style JSON | In Objective-C | In Swift `fill-translate` | `MGLFillStyleLayer.fillTranslation` | `MGLFillStyleLayer.fillTranslation` `fill-translate-anchor` | `MGLFillStyleLayer.fillTranslationAnchor` | `MGLFillStyleLayer.fillTranslationAnchor` -### Line style functions - -The runtime styling API introduces `MGLStyleFunction` to the macOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Line style layers In style JSON | In Objective-C | In Swift @@ -275,30 +203,6 @@ In style JSON | In Objective-C | In Swift `line-translate` | `MGLLineStyleLayer.lineTranslation` | `MGLLineStyleLayer.lineTranslation` `line-translate-anchor` | `MGLLineStyleLayer.lineTranslationAnchor` | `MGLLineStyleLayer.lineTranslationAnchor` -### Raster style functions - -The runtime styling API introduces `MGLStyleFunction` to the macOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Raster style layers In style JSON | In Objective-C | In Swift @@ -307,30 +211,6 @@ In style JSON | In Objective-C | In Swift `raster-brightness-min` | `MGLRasterStyleLayer.minimumRasterBrightness` | `MGLRasterStyleLayer.minimumRasterBrightness` `raster-hue-rotate` | `MGLRasterStyleLayer.rasterHueRotation` | `MGLRasterStyleLayer.rasterHueRotation` -### Symbol style functions - -The runtime styling API introduces `MGLStyleFunction` to the macOS SDK. -[Data-driven styling](data-driven-styling.html) expands `MGLStyleFunction`. -Individual style property documentation includes which subclasses of -`MGLStyleFunction` are enabled for that property. You can use `MGLStyleValue` -methods to create a `MGLStyleFunction`. - -In style specification | In the SDK | [MGLStyleValue valueWithInterpolationMode:...] ------------------------|-------------------------------|------------- -`zoom function` | `MGLCameraStyleFunction` | `cameraStops:options:` -`property function` | `MGLSourceStyleFunction` | `sourceStops:attributeName:options:` -`zoom-and-property functions`| `MGLCompositeStyleFunction` | `compositeStops:attributeName:options:` - -Data-driven styling also introduces interpolation mode, which defines the -relationship between style values and attributes or zoom levels. - -In style specification | In the SDK ------------------------------|----------- -`exponential` | `MGLInterpolationModeExponential` -`interval` | `MGLInterpolationModeInterval` -`categorical` | `MGLInterpolationModeCategorical` -`identity` | `MGLInterpolationModeIdentity` - ### Symbol style layers In style JSON | In Objective-C | In Swift @@ -363,10 +243,12 @@ In style JSON | In Objective-C | In Swift Each property representing a layout or paint attribute is set to an `MGLStyleValue` object, which is either an `MGLConstantStyleValue` object (for -constant values) or an `MGLStyleFunction` object (for zoom level functions). The +constant values) or an `MGLStyleFunction` object (for style functions). The style value object is a container for the raw value or function parameters that you want the attribute to be set to. +### Constant style values + In contrast to the JSON type that the style specification defines for each layout or paint property, the style value object often contains a more specific Foundation or Cocoa type. General rules for attribute types are listed below. @@ -397,6 +279,40 @@ offset or translation upward, while a negative `CGVector.dy` means an offset or translation downward. This is the reverse of how `CGVector` is interpreted on iOS. +### Style functions + +A _style function_ allows you to vary the value of a layout or paint attribute +based on the zoom level, data provided by content sources, or both. For more +information about style functions that incorporate data from sources, see +“[Data-Driven Styling](data-driven-styling.html)”. + +Each kind of style function is represented by a distinct class, but you +typically create style functions as you create any other style value, using +class methods on `MGLStyleValue`: + +In style specification | SDK class | SDK factory method +---------------------------|-----------------------------|------------------- +zoom function | `MGLCameraStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:cameraStops:options:]` +property function | `MGLSourceStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:sourceStops:attributeName:options:]` +zoom-and-property function | `MGLCompositeStyleFunction` | `+[MGLStyleValue valueWithInterpolationMode:compositeStops:attributeName:options:]` + +The documentation for each individual style layer property indicates the kinds +of style functions that are enabled for that property. + +When you create a style function, you specify an _interpolation mode_ and a +series of _stops_. Each stop determines the effective value displayed at a +particular zoom level (for camera functions) or the effective value on features +with a particular attribute value in the content source (for source functions). +The interpolation mode tells the SDK how to calculate the effective value +between any two stops: + +In style specification | In the SDK +-----------------------------|----------- +`exponential` | `MGLInterpolationModeExponential` +`interval` | `MGLInterpolationModeInterval` +`categorical` | `MGLInterpolationModeCategorical` +`identity` | `MGLInterpolationModeIdentity` + ## Filtering sources You can filter a shape or vector source by setting the From 228bff76020c48299a393fb324ff1fead06aeefb Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Sun, 10 May 2015 22:49:58 -0700 Subject: [PATCH 15/33] [ios] Replaced UIActionSheet, UIAlertView with UIAlertController --- platform/ios/src/MGLMapView.mm | 160 ++++++++++++++++++--------------- 1 file changed, 88 insertions(+), 72 deletions(-) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 6ce41d6fb..79467a065 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -220,10 +220,8 @@ public: @interface MGLMapView () @@ -236,7 +234,6 @@ public: @property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints; @property (nonatomic, readwrite) UIButton *attributionButton; @property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints; -@property (nonatomic) UIActionSheet *attributionSheet; @property (nonatomic, readwrite) MGLStyle *style; @property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer; @property (nonatomic) UIPanGestureRecognizer *pan; @@ -312,8 +309,6 @@ public: MGLCompassDirectionFormatter *_accessibilityCompassFormatter; - NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfos; - MGLReachability *_reachability; } @@ -897,11 +892,6 @@ public: _mbglMap->setSize([self size]); } - if (self.attributionSheet.visible) - { - [self.attributionSheet dismissWithClickedButtonIndex:self.attributionSheet.cancelButtonIndex animated:YES]; - } - if (self.compassView.alpha) { [self updateHeadingForDeviceOrientation]; @@ -1881,82 +1871,108 @@ public: - (void)showAttribution { - self.attributionSheet = [[UIActionSheet alloc] initWithTitle:NSLocalizedStringWithDefaultValue(@"SDK_NAME", nil, nil, @"Mapbox iOS SDK", @"Action sheet title") - delegate:self - cancelButtonTitle:NSLocalizedStringWithDefaultValue(@"CANCEL", nil, nil, @"Cancel", @"") - destructiveButtonTitle:nil - otherButtonTitles:nil]; - - _attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] linkColor:nil]; - for (MGLAttributionInfo *info in _attributionInfos) + NSString *title = NSLocalizedStringWithDefaultValue(@"SDK_NAME", nil, nil, @"Mapbox iOS SDK", @"Action sheet title"); + UIAlertController *attributionController = [UIAlertController alertControllerWithTitle:title + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + + NSArray *attributionInfos = [self.style attributionInfosWithFontSize:[UIFont buttonFontSize] + linkColor:nil]; + for (MGLAttributionInfo *info in attributionInfos) { NSString *title = [info.title.string mgl_titleCasedStringWithLocale:[NSLocale currentLocale]]; - [self.attributionSheet addButtonWithTitle:title]; - } - - [self.attributionSheet addButtonWithTitle:NSLocalizedStringWithDefaultValue(@"TELEMETRY_NAME", nil, nil, @"Mapbox Telemetry", @"Action in attribution sheet")]; - - [self.attributionSheet showFromRect:self.attributionButton.frame inView:self animated:YES]; -} - -- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex -{ - if (buttonIndex == actionSheet.numberOfButtons - 1) - { - NSString *message; - NSString *participate; - NSString *optOut; - - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"]) - { - message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message"); - participate = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button"); - optOut = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_OFF", nil, nil, @"Stop Participating", @"Telemetry prompt button"); - } - else - { - message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_MSG", nil, nil, @"You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message"); - participate = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_ON", nil, nil, @"Participate", @"Telemetry prompt button"); - optOut = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_OFF", nil, nil, @"Don’t Participate", @"Telemetry prompt button"); - } - - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedStringWithDefaultValue(@"TELEMETRY_TITLE", nil, nil, @"Make Mapbox Maps Better", @"Telemetry prompt title") - message:message - delegate:self - cancelButtonTitle:participate - otherButtonTitles:NSLocalizedStringWithDefaultValue(@"TELEMETRY_MORE", nil, nil, @"Tell Me More", @"Telemetry prompt button"), optOut, nil]; - [alert show]; - } - else if (buttonIndex > 0) - { - MGLAttributionInfo *info = _attributionInfos[buttonIndex + actionSheet.firstOtherButtonIndex]; - NSURL *url = info.URL; - if (url) - { - if (info.feedbackLink) + UIAlertAction *action = [UIAlertAction actionWithTitle:title + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { + NSURL *url = info.URL; + if (url) { - url = [info feedbackURLAtCenterCoordinate:self.centerCoordinate zoomLevel:self.zoomLevel]; + if (info.feedbackLink) + { + url = [info feedbackURLAtCenterCoordinate:self.centerCoordinate + zoomLevel:self.zoomLevel]; + } + [[UIApplication sharedApplication] openURL:url]; } - [[UIApplication sharedApplication] openURL:url]; - } + }]; + [attributionController addAction:action]; } + + NSString *telemetryTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_NAME", nil, nil, @"Mapbox Telemetry", @"Action in attribution sheet"); + UIAlertAction *telemetryAction = [UIAlertAction actionWithTitle:telemetryTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { + [self presentTelemetryAlertController]; + }]; + [attributionController addAction:telemetryAction]; + + NSString *cancelTitle = NSLocalizedStringWithDefaultValue(@"CANCEL", nil, nil, @"Cancel", @""); + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:cancelTitle + style:UIAlertActionStyleCancel + handler:NULL]; + [attributionController addAction:cancelAction]; + + attributionController.popoverPresentationController.sourceView = self; + attributionController.popoverPresentationController.sourceRect = self.attributionButton.frame; + + UIViewController *viewController = self.window.rootViewController; + if ([viewController isKindOfClass:[UINavigationController class]]) { + viewController = [(UINavigationController *)viewController viewControllers].firstObject; + } + [viewController presentViewController:attributionController + animated:YES + completion:NULL]; } -- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex +- (void)presentTelemetryAlertController { - if (buttonIndex == alertView.cancelButtonIndex) + NSString *title = NSLocalizedStringWithDefaultValue(@"TELEMETRY_TITLE", nil, nil, @"Make Mapbox Maps Better", @"Telemetry prompt title"); + NSString *message; + NSString *participateTitle; + NSString *declineTitle; + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"]) { - [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"]; + message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message"); + participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button"); + declineTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_OFF", nil, nil, @"Stop Participating", @"Telemetry prompt button"); } - else if (buttonIndex == alertView.firstOtherButtonIndex) + else { + message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_MSG", nil, nil, @"You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message"); + participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_ON", nil, nil, @"Participate", @"Telemetry prompt button"); + declineTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_DISABLED_OFF", nil, nil, @"Don’t Participate", @"Telemetry prompt button"); + } + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + NSString *moreTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_MORE", nil, nil, @"Tell Me More", @"Telemetry prompt button"); + UIAlertAction *moreAction = [UIAlertAction actionWithTitle:moreTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { [[UIApplication sharedApplication] openURL: [NSURL URLWithString:@"https://www.mapbox.com/telemetry/"]]; - } - else if (buttonIndex == alertView.firstOtherButtonIndex + 1) - { + }]; + [alertController addAction:moreAction]; + + UIAlertAction *declineAction = [UIAlertAction actionWithTitle:declineTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction * _Nonnull action) { [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"MGLMapboxMetricsEnabled"]; - } + }]; + [alertController addAction:declineAction]; + + UIAlertAction *participateAction = [UIAlertAction actionWithTitle:participateTitle + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * _Nonnull action) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"]; + }]; + [alertController addAction:participateAction]; + + [self.window.rootViewController presentViewController:alertController + animated:YES + completion:NULL]; } #pragma mark - Properties - From b10bbecf34a39ef6b60d95a358866570087e8679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Fri, 10 Mar 2017 17:58:56 -0800 Subject: [PATCH 16/33] [ios, macos] Updated changelogs --- platform/ios/CHANGELOG.md | 7 +++---- platform/macos/CHANGELOG.md | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 027689696..8b1d6219a 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -4,9 +4,9 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## 3.5.1 -### Other changes - * Fixed an issue that caused the return type of a map view delegate method to bridge incorrectly to applications written in Swift. ([#8541](https://github.com/mapbox/mapbox-gl-native/pull/8541)) +* Fixed a crash that could occur when calling `-[MGLShapeSource featuresMatchingPredicate:]` or `-[MGLVectorSource featuresInSourceLayersWithIdentifiers:predicate:]`. ([#8553](https://github.com/mapbox/mapbox-gl-native/pull/8553)) +* Fixed a crash that could occur after adding view-backed annotations to the map. ([#8513](https://github.com/mapbox/mapbox-gl-native/pull/8513)) ## 3.5.0 @@ -21,8 +21,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Added support for right-to-left text and Arabic ligatures in labels. ([#6984](https://github.com/mapbox/mapbox-gl-native/pull/6984), [#7123](https://github.com/mapbox/mapbox-gl-native/pull/7123)) * Improved the line wrapping behavior of point-placed labels, especially labels written in Chinese and Japanese. ([#6828](https://github.com/mapbox/mapbox-gl-native/pull/6828), [#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446)) * CJK characters now remain upright in vertically oriented labels that have line placement, such as road labels. ([#7114](https://github.com/mapbox/mapbox-gl-native/issues/7114)) -* Added Catalan, Chinese (Simplified and Traditional), Dutch, Finnish, French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Russian, Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999), -[#8113](https://github.com/mapbox/mapbox-gl-native/pull/8113), [#8256](https://github.com/mapbox/mapbox-gl-native/pull/8256)) +* Added Catalan, Chinese (Simplified and Traditional), Dutch, Finnish, French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Russian, Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999), [#8113](https://github.com/mapbox/mapbox-gl-native/pull/8113), [#8256](https://github.com/mapbox/mapbox-gl-native/pull/8256)) ### Styles diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 7e3eac987..fa5822863 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -2,13 +2,14 @@ ## 0.4.0 +This version of the Mapbox macOS SDK corresponds to version 3.5.1 of the Mapbox iOS SDK. + ### Internationalization * Added support for right-to-left text and Arabic ligatures in labels. ([#6984](https://github.com/mapbox/mapbox-gl-native/pull/6984), [#7123](https://github.com/mapbox/mapbox-gl-native/pull/7123)) * Improved the line wrapping behavior of point-placed labels, especially labels written in Chinese and Japanese. ([#6828](https://github.com/mapbox/mapbox-gl-native/pull/6828), [#7446](https://github.com/mapbox/mapbox-gl-native/pull/7446)) * CJK characters now remain upright in vertically oriented labels that have line placement, such as road labels. ([#7114](https://github.com/mapbox/mapbox-gl-native/issues/7114)) -* Added Catalan, Chinese (Simplified and Traditional), Dutch, Finnish, French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7503](https://github.com/mapbox/mapbox-gl-native/pull/7503), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999), -[#8113](https://github.com/mapbox/mapbox-gl-native/pull/8113), [#8256](https://github.com/mapbox/mapbox-gl-native/pull/8256)) +* Added Catalan, Chinese (Simplified and Traditional), Dutch, Finnish, French, German, Japanese, Lithuanian, Polish, Portuguese (Brazilian), Spanish, Swedish, Ukrainian, and Vietnamese localizations. ([#7316](https://github.com/mapbox/mapbox-gl-native/pull/7316), [#7503](https://github.com/mapbox/mapbox-gl-native/pull/7503), [#7899](https://github.com/mapbox/mapbox-gl-native/pull/7899), [#7999](https://github.com/mapbox/mapbox-gl-native/pull/7999), [#8113](https://github.com/mapbox/mapbox-gl-native/pull/8113), [#8256](https://github.com/mapbox/mapbox-gl-native/pull/8256)) ### Styles From 8af81ec88cf4b2dbb32256440ca16b8e9b67101f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 2 Apr 2017 00:40:35 -0700 Subject: [PATCH 17/33] macos-v0.4.0 --- platform/macos/Mapbox-macOS-SDK-symbols.podspec | 2 +- platform/macos/Mapbox-macOS-SDK.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec index c17e66551..4bac6dff2 100644 --- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec +++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.3.1' + version = '0.4.0' m.name = 'Mapbox-macOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec index a6f2d2838..a7ecb7423 100644 --- a/platform/macos/Mapbox-macOS-SDK.podspec +++ b/platform/macos/Mapbox-macOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.3.1' + version = '0.4.0' m.name = 'Mapbox-macOS-SDK' m.version = version From c1cd6759b4a87ef58442e864a192317284cf20ae Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 9 Mar 2017 07:53:02 -0800 Subject: [PATCH 18/33] [core] Extract and de-templatize several Program static methods --- cmake/core-files.cmake | 2 ++ src/mbgl/programs/program.hpp | 31 ++++--------------------------- src/mbgl/shaders/shaders.cpp | 33 +++++++++++++++++++++++++++++++++ src/mbgl/shaders/shaders.hpp | 15 +++++++++++++++ 4 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 src/mbgl/shaders/shaders.cpp create mode 100644 src/mbgl/shaders/shaders.hpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index d2a77aa3a..afc45a24c 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -209,6 +209,8 @@ set(MBGL_CORE_FILES src/mbgl/shaders/preludes.hpp src/mbgl/shaders/raster.cpp src/mbgl/shaders/raster.hpp + src/mbgl/shaders/shaders.cpp + src/mbgl/shaders/shaders.hpp src/mbgl/shaders/symbol_icon.cpp src/mbgl/shaders/symbol_icon.hpp src/mbgl/shaders/symbol_sdf.cpp diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index ffad767c3..8437e3a65 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -1,13 +1,9 @@ #pragma once #include -#include #include #include -#include - -#include -#include +#include namespace mbgl { @@ -34,30 +30,11 @@ public: ProgramType program; Program(gl::Context& context, const ProgramParameters& programParameters) - : program(context, vertexSource(programParameters), fragmentSource(programParameters)) + : program(context, + shaders::vertexSource(programParameters, Shaders::vertexSource), + shaders::fragmentSource(programParameters, Shaders::fragmentSource)) {} - static std::string pixelRatioDefine(const ProgramParameters& parameters) { - std::ostringstream pixelRatioSS; - pixelRatioSS.imbue(std::locale("C")); - pixelRatioSS.setf(std::ios_base::showpoint); - pixelRatioSS << parameters.pixelRatio; - return std::string("#define DEVICE_PIXEL_RATIO ") + pixelRatioSS.str() + "\n"; - } - - static std::string fragmentSource(const ProgramParameters& parameters) { - std::string source = pixelRatioDefine(parameters) + shaders::fragmentPrelude + Shaders::fragmentSource; - if (parameters.overdraw) { - assert(source.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); - source.replace(source.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); - } - return source; - } - - static std::string vertexSource(const ProgramParameters& parameters) { - return pixelRatioDefine(parameters) + shaders::vertexPrelude + Shaders::vertexSource; - } - template void draw(gl::Context& context, DrawMode drawMode, diff --git a/src/mbgl/shaders/shaders.cpp b/src/mbgl/shaders/shaders.cpp new file mode 100644 index 000000000..f7f5b4d44 --- /dev/null +++ b/src/mbgl/shaders/shaders.cpp @@ -0,0 +1,33 @@ +#include +#include +#include + +#include +#include + +namespace mbgl { +namespace shaders { + +static std::string pixelRatioDefine(const ProgramParameters& parameters) { + std::ostringstream pixelRatioSS; + pixelRatioSS.imbue(std::locale("C")); + pixelRatioSS.setf(std::ios_base::showpoint); + pixelRatioSS << parameters.pixelRatio; + return std::string("#define DEVICE_PIXEL_RATIO ") + pixelRatioSS.str() + "\n"; +} + +std::string fragmentSource(const ProgramParameters& parameters, const char* fragmentSource) { + std::string source = pixelRatioDefine(parameters) + fragmentPrelude + fragmentSource; + if (parameters.overdraw) { + assert(source.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); + source.replace(source.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); + } + return source; +} + +std::string vertexSource(const ProgramParameters& parameters, const char* vertexSource) { + return pixelRatioDefine(parameters) + vertexPrelude + vertexSource; +} + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/shaders/shaders.hpp b/src/mbgl/shaders/shaders.hpp new file mode 100644 index 000000000..e2912c568 --- /dev/null +++ b/src/mbgl/shaders/shaders.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace mbgl { + +class ProgramParameters; + +namespace shaders { + +std::string fragmentSource(const ProgramParameters&, const char* fragmentSource); +std::string vertexSource(const ProgramParameters&, const char* vertexSource); + +} // namespace shaders +} // namespace mbgl From f86333961eeacb9f2dd83a4c3680d30e06f947a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 15 Mar 2017 18:43:58 +0100 Subject: [PATCH 19/33] [core] cache binary shaders on Android --- cmake/core-files.cmake | 5 + cmake/test-files.cmake | 3 + include/mbgl/map/map.hpp | 3 +- .../mapbox/mapboxsdk/maps/NativeMapView.java | 11 +- platform/android/src/native_map_view.cpp | 26 ++-- platform/android/src/native_map_view.hpp | 8 +- proto/binary_program.proto | 18 +++ src/mbgl/gl/attribute.hpp | 13 +- src/mbgl/gl/context.cpp | 49 ++++++++ src/mbgl/gl/context.hpp | 10 ++ src/mbgl/gl/features.hpp | 7 ++ src/mbgl/gl/program.hpp | 30 +++-- src/mbgl/gl/program_binary.cpp | 24 ++++ src/mbgl/gl/program_binary.hpp | 27 ++++ src/mbgl/gl/types.hpp | 2 + src/mbgl/gl/uniform.hpp | 13 +- src/mbgl/map/map.cpp | 16 ++- src/mbgl/programs/binary_program.cpp | 117 ++++++++++++++++++ src/mbgl/programs/binary_program.hpp | 43 +++++++ src/mbgl/programs/program.hpp | 58 ++++++++- src/mbgl/programs/program_parameters.hpp | 15 ++- src/mbgl/programs/programs.hpp | 4 +- src/mbgl/renderer/painter.cpp | 16 ++- src/mbgl/renderer/painter.hpp | 2 +- src/mbgl/shaders/shaders.cpp | 14 +++ src/mbgl/shaders/shaders.hpp | 2 + src/mbgl/util/io.cpp | 10 ++ src/mbgl/util/io.hpp | 3 + test/programs/binary_program.test.cpp | 39 ++++++ 29 files changed, 541 insertions(+), 47 deletions(-) create mode 100644 proto/binary_program.proto create mode 100644 src/mbgl/gl/features.hpp create mode 100644 src/mbgl/gl/program_binary.cpp create mode 100644 src/mbgl/gl/program_binary.hpp create mode 100644 src/mbgl/programs/binary_program.cpp create mode 100644 src/mbgl/programs/binary_program.hpp create mode 100644 test/programs/binary_program.test.cpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index afc45a24c..61bc79c33 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -67,6 +67,7 @@ set(MBGL_CORE_FILES src/mbgl/gl/draw_mode.hpp src/mbgl/gl/extension.cpp src/mbgl/gl/extension.hpp + src/mbgl/gl/features.hpp src/mbgl/gl/framebuffer.hpp src/mbgl/gl/gl.cpp src/mbgl/gl/index_buffer.hpp @@ -75,6 +76,8 @@ set(MBGL_CORE_FILES src/mbgl/gl/object.hpp src/mbgl/gl/primitives.hpp src/mbgl/gl/program.hpp + src/mbgl/gl/program_binary.cpp + src/mbgl/gl/program_binary.hpp src/mbgl/gl/renderbuffer.hpp src/mbgl/gl/segment.cpp src/mbgl/gl/segment.hpp @@ -134,6 +137,8 @@ set(MBGL_CORE_FILES # programs src/mbgl/programs/attributes.hpp + src/mbgl/programs/binary_program.cpp + src/mbgl/programs/binary_program.hpp src/mbgl/programs/circle_program.cpp src/mbgl/programs/circle_program.hpp src/mbgl/programs/collision_box_program.cpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 873afa3d9..951514e38 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -38,6 +38,9 @@ set(MBGL_TEST_FILES test/math/minmax.test.cpp test/math/wrap.test.cpp + # programs + test/programs/binary_program.test.cpp + # sprite test/sprite/sprite_atlas.test.cpp test/sprite/sprite_image.test.cpp diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 02e14bea4..6b0717374 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -41,7 +41,8 @@ public: MapMode mapMode = MapMode::Continuous, GLContextMode contextMode = GLContextMode::Unique, ConstrainMode constrainMode = ConstrainMode::HeightOnly, - ViewportMode viewportMode = ViewportMode::Default); + ViewportMode viewportMode = ViewportMode::Default, + const std::string& programCacheDir = ""); ~Map(); // Register a callback that will get called (on the render thread) when all resources have 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 1460f08e1..a9394d0b6 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 @@ -97,7 +97,8 @@ final class NativeMapView { onMapChangedListeners = new CopyOnWriteArrayList<>(); this.mapView = mapView; - nativeInitialize(this, fileSource, pixelRatio, availableProcessors, totalMemory); + String programCacheDir = context.getCacheDir().getAbsolutePath(); + nativeInitialize(this, fileSource, pixelRatio, programCacheDir, availableProcessors, totalMemory); } // @@ -957,8 +958,12 @@ final class NativeMapView { // JNI methods // - private native void nativeInitialize(NativeMapView nativeMapView, FileSource fileSource, - float pixelRatio, int availableProcessors, long totalMemory); + private native void nativeInitialize(NativeMapView nativeMapView, + FileSource fileSource, + float pixelRatio, + String programCacheDir, + int availableProcessors, + long totalMemory); private native void nativeDestroy(); diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 696849b11..529ea2330 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -48,13 +48,18 @@ namespace mbgl { namespace android { -NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object _obj, jni::Object jFileSource, - jni::jfloat _pixelRatio, jni::jint _availableProcessors, jni::jlong _totalMemory) : - javaPeer(_obj.NewWeakGlobalRef(_env)), - pixelRatio(_pixelRatio), - availableProcessors(_availableProcessors), - totalMemory(_totalMemory), - threadPool(sharedThreadPool()) { +NativeMapView::NativeMapView(jni::JNIEnv& _env, + jni::Object _obj, + jni::Object jFileSource, + jni::jfloat _pixelRatio, + jni::String _programCacheDir, + jni::jint _availableProcessors, + jni::jlong _totalMemory) + : javaPeer(_obj.NewWeakGlobalRef(_env)), + pixelRatio(_pixelRatio), + availableProcessors(_availableProcessors), + totalMemory(_totalMemory), + threadPool(sharedThreadPool()) { // Get a reference to the JavaVM for callbacks if (_env.GetJavaVM(&vm) < 0) { @@ -65,8 +70,9 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env, jni::Object _obj, // Create the core map map = std::make_unique( *this, mbgl::Size{ static_cast(width), static_cast(height) }, - pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource) - , *threadPool, MapMode::Continuous); + pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource), *threadPool, + MapMode::Continuous, GLContextMode::Unique, ConstrainMode::HeightOnly, + ViewportMode::Default, jni::Make(_env, _programCacheDir)); //Calculate a fitting cache size based on device parameters float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; @@ -1398,7 +1404,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { // Register the peer jni::RegisterNativePeer(env, NativeMapView::javaClass, "nativePtr", - std::make_unique, jni::Object, jni::jfloat, jni::jint, jni::jlong>, + std::make_unique, jni::Object, jni::jfloat, jni::String, jni::jint, jni::jlong>, "nativeInitialize", "nativeDestroy", METHOD(&NativeMapView::render, "nativeRender"), diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 4afea036b..08133b85c 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -40,7 +40,13 @@ public: static void registerNative(jni::JNIEnv&); - NativeMapView(jni::JNIEnv&, jni::Object, jni::Object, jni::jfloat, jni::jint, jni::jlong); + NativeMapView(jni::JNIEnv&, + jni::Object, + jni::Object, + jni::jfloat pixelRatio, + jni::String programCacheDir, + jni::jint availableProcessors, + jni::jlong totalMemory); virtual ~NativeMapView(); diff --git a/proto/binary_program.proto b/proto/binary_program.proto new file mode 100644 index 000000000..9d06a209c --- /dev/null +++ b/proto/binary_program.proto @@ -0,0 +1,18 @@ +// Protocol Version 1 + +package mapboxgl.binary_program; + +option optimize_for = LITE_RUNTIME; + +message binding { + required string name = 1; + required uint32 value = 2; +} + +message binary_program { + required uint32 format = 1; + required bytes code = 2; + repeated binding attribute = 3; + repeated binding uniform = 4; + optional string identifier = 5; +} diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 43e2c2d79..e23c4f9e4 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -7,6 +7,7 @@ #include #include +#include #include namespace mbgl { @@ -241,16 +242,26 @@ public: using VariableBindings = IndexedTuple< TypeList, TypeList...>>; + using NamedLocations = std::vector>; using Vertex = detail::Vertex; template static constexpr std::size_t Index = TypeIndex::value; - static Locations locations(const ProgramID& id) { + static Locations bindLocations(const ProgramID& id) { return Locations { bindAttributeLocation(id, Index, As::name())... }; } + template + static Locations loadNamedLocations(const Program& program) { + return Locations{ program.attributeLocation(As::name())... }; + } + + static NamedLocations getNamedLocations(const Locations& locations) { + return NamedLocations{ { As::name(), locations.template get() }... }; + } + template static Bindings allVariableBindings(const VertexBuffer& buffer) { return Bindings { As::variableBinding(buffer, Index)... }; diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 9c2031ccf..97ebf687f 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,8 @@ static_assert(std::is_same, GLenum>::value static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); +static_assert(std::is_same::value, "OpenGL type mismatch"); + Context::~Context() { reset(); } @@ -72,9 +75,27 @@ UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentSha return result; } +#if MBGL_HAS_BINARY_PROGRAMS +UniqueProgram Context::createProgram(BinaryProgramFormat binaryFormat, + const std::string& binaryProgram) { + UniqueProgram result{ MBGL_CHECK_ERROR(glCreateProgram()), { this } }; + MBGL_CHECK_ERROR(ProgramBinary(result, static_cast(binaryFormat), binaryProgram.data(), + static_cast(binaryProgram.size()))); + verifyProgramLinkage(result); + return result; +} +#else +UniqueProgram Context::createProgram(BinaryProgramFormat, const std::string&) { + throw std::runtime_error("binary programs are not supported"); +} +#endif + void Context::linkProgram(ProgramID program_) { MBGL_CHECK_ERROR(glLinkProgram(program_)); + verifyProgramLinkage(program_); +} +void Context::verifyProgramLinkage(ProgramID program_) { GLint status; MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status)); if (status == GL_TRUE) { @@ -129,6 +150,34 @@ bool Context::supportsVertexArrays() const { !disableVAOExtension; } +#if MBGL_HAS_BINARY_PROGRAMS +bool Context::supportsProgramBinaries() const { + return gl::ProgramBinary && gl::GetProgramBinary; +} + +optional> +Context::getBinaryProgram(ProgramID program_) const { + if (!supportsProgramBinaries()) { + return {}; + } + GLint binaryLength; + MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binaryLength)); + std::string binary; + binary.resize(binaryLength); + GLenum binaryFormat; + MBGL_CHECK_ERROR(GetProgramBinary(program_, binaryLength, &binaryLength, &binaryFormat, + const_cast(binary.data()))); + if (size_t(binaryLength) != binary.size()) { + return {}; + } + return { { binaryFormat, std::move(binary) } }; +} +#else +optional> Context::getBinaryProgram(ProgramID) const { + return {}; +} +#endif + UniqueVertexArray Context::createVertexArray() { assert(supportsVertexArrays()); VertexArrayID id = 0; diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 9d3ecec66..fd6683a0c 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -37,12 +38,21 @@ public: UniqueShader createShader(ShaderType type, const std::string& source); UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader); + UniqueProgram createProgram(BinaryProgramFormat binaryFormat, const std::string& binaryProgram); + void verifyProgramLinkage(ProgramID); void linkProgram(ProgramID); UniqueTexture createTexture(); bool supportsVertexArrays() const; UniqueVertexArray createVertexArray(); +#if MBGL_HAS_BINARY_PROGRAMS + bool supportsProgramBinaries() const; +#else + constexpr bool supportsProgramBinaries() const { return false; } +#endif + optional> getBinaryProgram(ProgramID) const; + template VertexBuffer createVertexBuffer(VertexVector&& v) { return VertexBuffer { diff --git a/src/mbgl/gl/features.hpp b/src/mbgl/gl/features.hpp new file mode 100644 index 000000000..04dc4fa02 --- /dev/null +++ b/src/mbgl/gl/features.hpp @@ -0,0 +1,7 @@ +#pragma once + +#if __APPLE__ + #define MBGL_HAS_BINARY_PROGRAMS 0 +#else + #define MBGL_HAS_BINARY_PROGRAMS 1 +#endif \ No newline at end of file diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index fa0470796..7d7fca526 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -24,11 +24,29 @@ public: using AttributeBindings = typename Attributes::Bindings; Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource) - : vertexShader(context.createShader(ShaderType::Vertex, vertexSource)), - fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)), - program(context.createProgram(vertexShader, fragmentShader)), - attributeLocations(Attributes::locations(program)), - uniformsState((context.linkProgram(program), Uniforms::state(program))) {} + : program( + context.createProgram(context.createShader(ShaderType::Vertex, vertexSource), + context.createShader(ShaderType::Fragment, fragmentSource))), + attributeLocations(Attributes::bindLocations(program)), + uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))) { + } + + template + Program(Context& context, const BinaryProgram& binaryProgram) + : program(context.createProgram(binaryProgram.format(), binaryProgram.code())), + attributeLocations(Attributes::loadNamedLocations(binaryProgram)), + uniformsState(Uniforms::loadNamedLocations(binaryProgram)) { + } + + template + optional get(Context& context, const std::string& identifier) const { + if (auto binaryProgram = context.getBinaryProgram(program)) { + return BinaryProgram{ binaryProgram->first, std::move(binaryProgram->second), + identifier, Attributes::getNamedLocations(attributeLocations), + Uniforms::getNamedLocations(uniformsState) }; + } + return {}; + } template void draw(Context& context, @@ -64,8 +82,6 @@ public: } private: - UniqueShader vertexShader; - UniqueShader fragmentShader; UniqueProgram program; typename Attributes::Locations attributeLocations; diff --git a/src/mbgl/gl/program_binary.cpp b/src/mbgl/gl/program_binary.cpp new file mode 100644 index 000000000..ad147c819 --- /dev/null +++ b/src/mbgl/gl/program_binary.cpp @@ -0,0 +1,24 @@ +#include + +#if MBGL_HAS_BINARY_PROGRAMS + +namespace mbgl { +namespace gl { + +ExtensionFunction< + void(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)> + GetProgramBinary({ + { "GL_OES_get_program_binary", "glGetProgramBinaryOES" }, + { "GL_ARB_get_program_binary", "glGetProgramBinary" }, + }); + +ExtensionFunction + ProgramBinary({ + { "GL_OES_get_program_binary", "glProgramBinaryOES" }, + { "GL_ARB_get_program_binary", "glProgramBinary" }, + }); + +} // namespace gl +} // namespace mbgl + +#endif diff --git a/src/mbgl/gl/program_binary.hpp b/src/mbgl/gl/program_binary.hpp new file mode 100644 index 000000000..e888ed3d4 --- /dev/null +++ b/src/mbgl/gl/program_binary.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#if MBGL_HAS_BINARY_PROGRAMS + +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF + +namespace mbgl { +namespace gl { + +extern ExtensionFunction + GetProgramBinary; + +extern ExtensionFunction + ProgramBinary; + +} // namespace gl +} // namespace mbgl + +#endif diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index 565ca5754..7d436693c 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -73,5 +73,7 @@ constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) #endif // MBGL_USE_GLES2 +using BinaryProgramFormat = uint32_t; + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 92136b61c..34a32aeee 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace mbgl { @@ -66,11 +67,21 @@ public: using Types = TypeList; using State = IndexedTuple, TypeList>; using Values = IndexedTuple, TypeList>; + using NamedLocations = std::vector>; - static State state(const ProgramID& id) { + static State bindLocations(const ProgramID& id) { return State { { uniformLocation(id, Us::name()) }... }; } + template + static State loadNamedLocations(const Program& program) { + return State{ { program.uniformLocation(Us::name()) }... }; + } + + static NamedLocations getNamedLocations(const State& state) { + return NamedLocations{ { Us::name(), state.template get().location }... }; + } + static void bind(State& state, Values&& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index f4e994c93..aca1b77e7 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -56,7 +56,8 @@ public: MapMode, GLContextMode, ConstrainMode, - ViewportMode); + ViewportMode, + const std::string& programCacheDir); void onSourceAttributionChanged(style::Source&, const std::string&) override; void onUpdate(Update) override; @@ -80,6 +81,7 @@ public: const MapMode mode; const GLContextMode contextMode; const float pixelRatio; + const std::string programCacheDir; MapDebugOptions debugOptions { MapDebugOptions::NoDebug }; @@ -111,7 +113,8 @@ Map::Map(Backend& backend, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode, - ViewportMode viewportMode) + ViewportMode viewportMode, + const std::string& programCacheDir) : impl(std::make_unique(*this, backend, pixelRatio, @@ -120,7 +123,8 @@ Map::Map(Backend& backend, mapMode, contextMode, constrainMode, - viewportMode)) { + viewportMode, + programCacheDir)) { impl->transform.resize(size); } @@ -132,7 +136,8 @@ Map::Impl::Impl(Map& map_, MapMode mode_, GLContextMode contextMode_, ConstrainMode constrainMode_, - ViewportMode viewportMode_) + ViewportMode viewportMode_, + const std::string& programCacheDir_) : map(map_), backend(backend_), fileSource(fileSource_), @@ -143,6 +148,7 @@ Map::Impl::Impl(Map& map_, mode(mode_), contextMode(contextMode_), pixelRatio(pixelRatio_), + programCacheDir(programCacheDir_), annotationManager(std::make_unique(pixelRatio)), asyncInvalidate([this] { if (mode == MapMode::Continuous) { @@ -259,7 +265,7 @@ void Map::Impl::render(View& view) { updateFlags = Update::Nothing; if (!painter) { - painter = std::make_unique(backend.getContext(), transform.getState(), pixelRatio); + painter = std::make_unique(backend.getContext(), transform.getState(), pixelRatio, programCacheDir); } if (mode == MapMode::Continuous) { diff --git a/src/mbgl/programs/binary_program.cpp b/src/mbgl/programs/binary_program.cpp new file mode 100644 index 000000000..3b37cfa44 --- /dev/null +++ b/src/mbgl/programs/binary_program.cpp @@ -0,0 +1,117 @@ +#include + +#include +#include + +template +static std::pair parseBinding(protozero::pbf_reader&& pbf) { + bool hasName = false, hasValue = false; + std::pair binding; + while (pbf.next()) { + switch (pbf.tag()) { + case 1: // name + binding.first = pbf.get_string(); + hasName = true; + break; + case 2: // value + binding.second = pbf.get_uint32(); + hasValue = true; + break; + default: + pbf.skip(); + break; + } + } + if (!hasName || !hasValue) { + throw std::runtime_error("BinaryProgram binding is missing required fields"); + } + return binding; +} + +namespace mbgl { + +BinaryProgram::BinaryProgram(std::string&& data) { + bool hasFormat = false, hasCode = false; + protozero::pbf_reader pbf(data); + while (pbf.next()) { + switch (pbf.tag()) { + case 1: // format + binaryFormat = pbf.get_uint32(); + hasFormat = true; + break; + case 2: // code + binaryCode = pbf.get_bytes(); + hasCode = true; + break; + case 3: // variable + attributes.emplace_back(parseBinding(pbf.get_message())); + break; + case 4: // uniform + uniforms.emplace_back(parseBinding(pbf.get_message())); + break; + case 5: // identifier + default: + binaryIdentifier = pbf.get_string(); + break; + } + } + + if (!hasFormat || !hasCode) { + throw std::runtime_error("BinaryProgram is missing required fields"); + } +} + +BinaryProgram::BinaryProgram( + gl::BinaryProgramFormat binaryFormat_, + std::string&& binaryCode_, + const std::string& binaryIdentifier_, + std::vector>&& attributes_, + std::vector>&& uniforms_) + : binaryFormat(binaryFormat_), + binaryCode(std::move(binaryCode_)), + binaryIdentifier(binaryIdentifier_), + attributes(std::move(attributes_)), + uniforms(std::move(uniforms_)) { +} + +std::string BinaryProgram::serialize() const { + std::string data; + data.reserve(32 + binaryCode.size() + uniforms.size() * 32 + attributes.size() * 32); + protozero::pbf_writer pbf(data); + pbf.add_uint32(1 /* format */, binaryFormat); + pbf.add_bytes(2 /* code */, binaryCode.data(), binaryCode.size()); + for (const auto& binding : attributes) { + protozero::pbf_writer pbf_binding(pbf, 3 /* attribute */); + pbf_binding.add_string(1 /* name */, binding.first); + pbf_binding.add_uint32(2 /* value */, binding.second); + } + for (const auto& binding : uniforms) { + protozero::pbf_writer pbf_binding(pbf, 4 /* uniform */); + pbf_binding.add_string(1 /* name */, binding.first); + pbf_binding.add_uint32(2 /* value */, binding.second); + } + if (!binaryIdentifier.empty()) { + pbf.add_string(5 /* identifier */, binaryIdentifier); + } + return data; +} + +gl::AttributeLocation BinaryProgram::attributeLocation(const std::string& name) const { + for (const auto& pair : attributes) { + if (pair.first == name) { + return pair.second; + } + } + return {}; +} + +gl::UniformLocation BinaryProgram::uniformLocation(const std::string& name) const { + for (const auto& pair : uniforms) { + if (pair.first == name) { + return pair.second; + } + } + return {}; +} + +} // namespace mbgl diff --git a/src/mbgl/programs/binary_program.hpp b/src/mbgl/programs/binary_program.hpp new file mode 100644 index 000000000..8ff3863dc --- /dev/null +++ b/src/mbgl/programs/binary_program.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { + +class BinaryProgram { +public: + // Initialize a BinaryProgram object from a serialized represenation. + BinaryProgram(std::string&& data); + + BinaryProgram(gl::BinaryProgramFormat, + std::string&& binaryCode, + const std::string& binaryIdentifier, + std::vector>&&, + std::vector>&&); + + std::string serialize() const; + + gl::BinaryProgramFormat format() const { + return binaryFormat; + } + const std::string& code() const { + return binaryCode; + } + const std::string& identifier() const { + return binaryIdentifier; + } + gl::AttributeLocation attributeLocation(const std::string& name) const; + gl::UniformLocation uniformLocation(const std::string& name) const; + +private: + gl::BinaryProgramFormat binaryFormat = 0; + std::string binaryCode; + std::string binaryIdentifier; + std::vector> attributes; + std::vector> uniforms; +}; + +} // namespace mbgl diff --git a/src/mbgl/programs/program.hpp b/src/mbgl/programs/program.hpp index 8437e3a65..8925bc75d 100644 --- a/src/mbgl/programs/program.hpp +++ b/src/mbgl/programs/program.hpp @@ -1,9 +1,13 @@ #pragma once #include +#include +#include #include +#include #include #include +#include namespace mbgl { @@ -30,10 +34,56 @@ public: ProgramType program; Program(gl::Context& context, const ProgramParameters& programParameters) - : program(context, - shaders::vertexSource(programParameters, Shaders::vertexSource), - shaders::fragmentSource(programParameters, Shaders::fragmentSource)) - {} + : program([&] { +#if MBGL_HAS_BINARY_PROGRAMS + if (!programParameters.cacheDir.empty() && context.supportsProgramBinaries()) { + const std::string vertexSource = + shaders::vertexSource(programParameters, Shaders::vertexSource); + const std::string fragmentSource = + shaders::fragmentSource(programParameters, Shaders::fragmentSource); + const std::string cachePath = + shaders::programCachePath(programParameters, Shaders::name); + const std::string identifier = + shaders::programIdentifier(vertexSource, fragmentSource); + + try { + if (auto cachedBinaryProgram = util::readFile(cachePath)) { + const BinaryProgram binaryProgram(std::move(*cachedBinaryProgram)); + if (binaryProgram.identifier() == identifier) { + return ProgramType{ context, binaryProgram }; + } else { + Log::Warning(Event::OpenGL, + "Cached program %s changed. Recompilation required.", + Shaders::name); + } + } + } catch (std::runtime_error& error) { + Log::Warning(Event::OpenGL, "Could not load cached program: %s", + error.what()); + } + + // Compile the shader + ProgramType result{ context, vertexSource, fragmentSource }; + + try { + if (const auto binaryProgram = + result.template get(context, identifier)) { + 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()); + } + + return std::move(result); + } +#endif + return ProgramType{ + context, shaders::vertexSource(programParameters, Shaders::vertexSource), + shaders::fragmentSource(programParameters, Shaders::fragmentSource) + }; + }()) { + } template void draw(gl::Context& context, diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp index ad8cbf1bf..b91b41f35 100644 --- a/src/mbgl/programs/program_parameters.hpp +++ b/src/mbgl/programs/program_parameters.hpp @@ -1,15 +1,20 @@ #pragma once +#include + namespace mbgl { class ProgramParameters { public: - ProgramParameters(float pixelRatio_ = 1.0, bool overdraw_ = false) - : pixelRatio(pixelRatio_), - overdraw(overdraw_) {} + ProgramParameters(float pixelRatio_ = 1.0, + bool overdraw_ = false, + const std::string& cacheDir_ = "") + : pixelRatio(pixelRatio_), overdraw(overdraw_), cacheDir(cacheDir_) { + } - float pixelRatio; - bool overdraw; + const float pixelRatio; + const bool overdraw; + const std::string cacheDir; }; } // namespace mbgl diff --git a/src/mbgl/programs/programs.hpp b/src/mbgl/programs/programs.hpp index 742c5a221..dbf5b9e87 100644 --- a/src/mbgl/programs/programs.hpp +++ b/src/mbgl/programs/programs.hpp @@ -26,8 +26,8 @@ public: symbolIcon(context, programParameters), symbolIconSDF(context, programParameters), symbolGlyph(context, programParameters), - debug(context, ProgramParameters(programParameters.pixelRatio, false)), - collisionBox(context, ProgramParameters(programParameters.pixelRatio, false)) { + debug(context, ProgramParameters(programParameters.pixelRatio, false, programParameters.cacheDir)), + collisionBox(context, ProgramParameters(programParameters.pixelRatio, false, programParameters.cacheDir)) { } CircleProgram circle; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 27d24d14a..754959438 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -33,6 +33,8 @@ #include +#include + #include #include #include @@ -77,7 +79,10 @@ static gl::VertexVector rasterVertices() { return result; } -Painter::Painter(gl::Context& context_, const TransformState& state_, float pixelRatio) +Painter::Painter(gl::Context& context_, + const TransformState& state_, + float pixelRatio, + const std::string& programCacheDir) : context(context_), state(state_), tileVertexBuffer(context.createVertexBuffer(tileVertices())), @@ -91,12 +96,11 @@ Painter::Painter(gl::Context& context_, const TransformState& state_, float pixe gl::debugging::enable(); - ProgramParameters programParameters{ pixelRatio, false }; - programs = std::make_unique(context, programParameters); + programs = std::make_unique(context, + ProgramParameters{ pixelRatio, false, programCacheDir }); #ifndef NDEBUG - - ProgramParameters programParametersOverdraw{ pixelRatio, true }; - overdrawPrograms = std::make_unique(context, programParametersOverdraw); + overdrawPrograms = + std::make_unique(context, ProgramParameters{ pixelRatio, true, programCacheDir }); #endif } diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 91f329a6e..3dcc1d5d4 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -68,7 +68,7 @@ struct FrameData { class Painter : private util::noncopyable { public: - Painter(gl::Context&, const TransformState&, float pixelRatio); + Painter(gl::Context&, const TransformState&, float pixelRatio, const std::string& programCacheDir); ~Painter(); void render(const style::Style&, diff --git a/src/mbgl/shaders/shaders.cpp b/src/mbgl/shaders/shaders.cpp index f7f5b4d44..03d796edb 100644 --- a/src/mbgl/shaders/shaders.cpp +++ b/src/mbgl/shaders/shaders.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace mbgl { namespace shaders { @@ -29,5 +30,18 @@ std::string vertexSource(const ProgramParameters& parameters, const char* vertex return pixelRatioDefine(parameters) + vertexPrelude + vertexSource; } +std::string programCachePath(const ProgramParameters& parameters, const char* name) { + return parameters.cacheDir + "/com.mapbox.gl.shader." + name + + (parameters.overdraw ? ".overdraw.pbf" : ".pbf"); +} + +std::string programIdentifier(const std::string& vertexSource, const std::string& fragmentSource) { + std::ostringstream ss; + ss << std::setfill('0') << std::setw(sizeof(size_t) * 2) << std::hex; + ss << std::hash()(vertexSource); + ss << std::hash()(fragmentSource); + return ss.str(); +} + } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/shaders.hpp b/src/mbgl/shaders/shaders.hpp index e2912c568..126c64bb9 100644 --- a/src/mbgl/shaders/shaders.hpp +++ b/src/mbgl/shaders/shaders.hpp @@ -10,6 +10,8 @@ namespace shaders { std::string fragmentSource(const ProgramParameters&, const char* fragmentSource); std::string vertexSource(const ProgramParameters&, const char* vertexSource); +std::string programCachePath(const ProgramParameters&, const char* name); +std::string programIdentifier(const std::string& vertexSource, const std::string& fragmentSource); } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/util/io.cpp b/src/mbgl/util/io.cpp index f37ce09cf..9adc3b898 100644 --- a/src/mbgl/util/io.cpp +++ b/src/mbgl/util/io.cpp @@ -32,6 +32,16 @@ std::string read_file(const std::string &filename) { } } +optional readFile(const std::string &filename) { + std::ifstream file(filename); + if (file.good()) { + std::stringstream data; + data << file.rdbuf(); + return data.str(); + } + return {}; +} + void deleteFile(const std::string& filename) { const int ret = unlink(filename.c_str()); if (ret == -1) { diff --git a/src/mbgl/util/io.hpp b/src/mbgl/util/io.hpp index 795a46532..847271acf 100644 --- a/src/mbgl/util/io.hpp +++ b/src/mbgl/util/io.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -15,6 +17,7 @@ struct IOException : std::runtime_error { void write_file(const std::string &filename, const std::string &data); std::string read_file(const std::string &filename); +optional readFile(const std::string &filename); void deleteFile(const std::string& filename); } // namespace util diff --git a/test/programs/binary_program.test.cpp b/test/programs/binary_program.test.cpp new file mode 100644 index 000000000..ce544e765 --- /dev/null +++ b/test/programs/binary_program.test.cpp @@ -0,0 +1,39 @@ +#include + +#include + +using namespace mbgl; + +TEST(BinaryProgram, ObtainValues) { + const BinaryProgram binaryProgram{ 42, + "binary code", + "identifier", + { { "a_pos", 1 }, { "a_data", 4 } }, + { { "u_world", 1 }, { "u_ratio", 3 } } }; + + EXPECT_EQ(42u, binaryProgram.format()); + EXPECT_EQ("binary code", binaryProgram.code()); + EXPECT_EQ("identifier", binaryProgram.identifier()); + EXPECT_EQ(1, binaryProgram.attributeLocation("a_pos")); + EXPECT_EQ(0, binaryProgram.attributeLocation("u_world")); + EXPECT_EQ(4, binaryProgram.attributeLocation("a_data")); + EXPECT_EQ(1, binaryProgram.uniformLocation("u_world")); + EXPECT_EQ(3, binaryProgram.uniformLocation("u_ratio")); + EXPECT_EQ(0, binaryProgram.uniformLocation("a_data")); + + auto serialized = binaryProgram.serialize(); + + const BinaryProgram binaryProgram2(std::move(serialized)); + + EXPECT_EQ(42u, binaryProgram2.format()); + EXPECT_EQ("binary code", binaryProgram2.code()); + EXPECT_EQ("identifier", binaryProgram2.identifier()); + EXPECT_EQ(1, binaryProgram2.attributeLocation("a_pos")); + EXPECT_EQ(0, binaryProgram2.attributeLocation("u_world")); + EXPECT_EQ(4, binaryProgram2.attributeLocation("a_data")); + EXPECT_EQ(1, binaryProgram2.uniformLocation("u_world")); + EXPECT_EQ(3, binaryProgram2.uniformLocation("u_ratio")); + EXPECT_EQ(0, binaryProgram2.uniformLocation("a_data")); + + EXPECT_THROW(BinaryProgram(""), std::runtime_error); +} From fc382f7108f039480c7652557722e413e2626ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 2 Apr 2017 04:21:00 -0700 Subject: [PATCH 20/33] [macos] Fixed broken images in DDS guide --- .../docs/img/data-driven-styling/categorical1.png | Bin .../docs/img/data-driven-styling/categorical2.png | Bin .../docs/img/data-driven-styling/citibikes.png | Bin .../data-driven-styling/exponential-function-1.png | Bin .../data-driven-styling/exponential-function.png | Bin .../docs/img/data-driven-styling/exponential.png | Bin .../docs/img/data-driven-styling/identity.png | Bin .../docs/img/data-driven-styling/interval.png | Bin .../img/data-driven-styling/polylineExample.png | Bin platform/ios/scripts/document.sh | 3 ++- platform/macos/scripts/document.sh | 3 ++- 11 files changed, 4 insertions(+), 2 deletions(-) rename platform/{ios => darwin}/docs/img/data-driven-styling/categorical1.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/categorical2.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/citibikes.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/exponential-function-1.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/exponential-function.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/exponential.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/identity.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/interval.png (100%) rename platform/{ios => darwin}/docs/img/data-driven-styling/polylineExample.png (100%) diff --git a/platform/ios/docs/img/data-driven-styling/categorical1.png b/platform/darwin/docs/img/data-driven-styling/categorical1.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/categorical1.png rename to platform/darwin/docs/img/data-driven-styling/categorical1.png diff --git a/platform/ios/docs/img/data-driven-styling/categorical2.png b/platform/darwin/docs/img/data-driven-styling/categorical2.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/categorical2.png rename to platform/darwin/docs/img/data-driven-styling/categorical2.png diff --git a/platform/ios/docs/img/data-driven-styling/citibikes.png b/platform/darwin/docs/img/data-driven-styling/citibikes.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/citibikes.png rename to platform/darwin/docs/img/data-driven-styling/citibikes.png diff --git a/platform/ios/docs/img/data-driven-styling/exponential-function-1.png b/platform/darwin/docs/img/data-driven-styling/exponential-function-1.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/exponential-function-1.png rename to platform/darwin/docs/img/data-driven-styling/exponential-function-1.png diff --git a/platform/ios/docs/img/data-driven-styling/exponential-function.png b/platform/darwin/docs/img/data-driven-styling/exponential-function.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/exponential-function.png rename to platform/darwin/docs/img/data-driven-styling/exponential-function.png diff --git a/platform/ios/docs/img/data-driven-styling/exponential.png b/platform/darwin/docs/img/data-driven-styling/exponential.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/exponential.png rename to platform/darwin/docs/img/data-driven-styling/exponential.png diff --git a/platform/ios/docs/img/data-driven-styling/identity.png b/platform/darwin/docs/img/data-driven-styling/identity.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/identity.png rename to platform/darwin/docs/img/data-driven-styling/identity.png diff --git a/platform/ios/docs/img/data-driven-styling/interval.png b/platform/darwin/docs/img/data-driven-styling/interval.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/interval.png rename to platform/darwin/docs/img/data-driven-styling/interval.png diff --git a/platform/ios/docs/img/data-driven-styling/polylineExample.png b/platform/darwin/docs/img/data-driven-styling/polylineExample.png similarity index 100% rename from platform/ios/docs/img/data-driven-styling/polylineExample.png rename to platform/darwin/docs/img/data-driven-styling/polylineExample.png diff --git a/platform/ios/scripts/document.sh b/platform/ios/scripts/document.sh index d66742a33..170debb62 100755 --- a/platform/ios/scripts/document.sh +++ b/platform/ios/scripts/document.sh @@ -30,7 +30,8 @@ sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^## /q' -e 'p' -e 'ba' -e '}' platform/i rm -rf ${OUTPUT} mkdir -p ${OUTPUT} -cp -r platform/ios/docs/img "${OUTPUT}/img" +cp -r platform/darwin/docs/img "${OUTPUT}" +cp -r platform/ios/docs/img "${OUTPUT}" DEFAULT_THEME="platform/darwin/docs/theme" THEME=${JAZZY_THEME:-$DEFAULT_THEME} diff --git a/platform/macos/scripts/document.sh b/platform/macos/scripts/document.sh index 69c9aaa87..2e53dc359 100755 --- a/platform/macos/scripts/document.sh +++ b/platform/macos/scripts/document.sh @@ -36,7 +36,8 @@ sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^## /q' -e 'p' -e 'ba' -e '}' platform/m rm -rf ${OUTPUT} mkdir -p ${OUTPUT} -cp -r platform/macos/docs/img "${OUTPUT}/img" +cp -r platform/darwin/docs/img "${OUTPUT}" +cp -r platform/macos/docs/img "${OUTPUT}" jazzy \ --config platform/macos/jazzy.yml \ From 6718d2cc5145497bb7503ab0bb9db4cbe6e1deb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sun, 2 Apr 2017 04:21:27 -0700 Subject: [PATCH 21/33] [macos] Removed MGLUserTrackingMode from jazzy ToC --- platform/macos/jazzy.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml index 932311971..fd6052c9f 100644 --- a/platform/macos/jazzy.yml +++ b/platform/macos/jazzy.yml @@ -27,7 +27,6 @@ custom_categories: - MGLMapCamera - MGLMapView - MGLMapViewDelegate - - MGLUserTrackingMode - name: Shapes and Annotations children: - MGLAnnotation From e34b4718422438af365fe5ede67d1c490e95d9cc Mon Sep 17 00:00:00 2001 From: Tobrun Date: Tue, 4 Apr 2017 21:14:32 +0200 Subject: [PATCH 22/33] Release android v5.0.2 (#8629) * [android] - update CHANGELOG.md for v5.0.2 release * [android] - bump version name to 5.0.2 * [android] - fixup javadoc errors * bump SNAPSHOT version --- platform/android/CHANGELOG.md | 1 + .../com/mapbox/mapboxsdk/camera/CameraPosition.java | 2 +- .../mapbox/mapboxsdk/location/LocationSource.java | 9 ++++----- .../mapboxsdk/style/sources/GeoJsonSource.java | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 01d7b1ab5..2b0e40f21 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -6,6 +6,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to 5.0.2 is a patch release that contains the following changes: +* Binary shader caching [#8604](https://github.com/mapbox/mapbox-gl-native/pull/8604) * Fix resource transform callback [#8582](https://github.com/mapbox/mapbox-gl-native/pull/8582) * Restore onTouch behaviour to 4.x version [#8585](https://github.com/mapbox/mapbox-gl-native/pull/8585) * Restore anchoring after updating MarkerView Icon [#8519](https://github.com/mapbox/mapbox-gl-native/pull/8519) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java index 74170bb72..a8fc58d51 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -293,7 +293,7 @@ public final class CameraPosition implements Parcelable { * Set the tilt in degrees *

* value is clamped to 0 and 60. - *

+ *

* * @param tilt Tilt value * @return Builder diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java index f41a022fa..dd6e43d06 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java @@ -18,11 +18,10 @@ import java.lang.ref.WeakReference; /** * Manages locational updates. Contains methods to register and unregister location listeners. *
    - *
  • You can register a {@link LocationEngineListener} with - * {@link #addLocationEngineListener(LocationEngineListener)} to receive - * location updates.
  • - *
  • You can unregister a {@link LocationEngineListener} with - * {@link #removeLocationEngineListener(LocationEngineListener)} to stop receiving location updates.
  • + *
  • You can register a LocationEngineListener with LocationSource#addLocationEngineListener(LocationEngineListener) + * to receive location updates.
  • + *
  • You can unregister a LocationEngineListener with + * LocationEngine#removeLocationEngineListener(LocationEngineListener)} to stop receiving location updates.
  • *
*

* Note: If registering a listener in your Activity.onStart() implementation, you should unregister it in diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index b25359571..5e9ca7d0a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -42,7 +42,7 @@ public class GeoJsonSource extends Source { } /** - * Create an empty GeoJsonSource with non-default {@link GeoJsonOptions} + * Create an empty GeoJsonSource with non-default GeoJsonOptions. * * @param id the source id * @param options options @@ -67,7 +67,7 @@ public class GeoJsonSource extends Source { } /** - * Create a GeoJsonSource from a raw json string and non-default {@link GeoJsonOptions} + * Create a GeoJsonSource from a raw json string and non-default GeoJsonOptions * * @param id the source id * @param geoJson raw Json body @@ -93,7 +93,7 @@ public class GeoJsonSource extends Source { } /** - * Create a GeoJsonSource from a remote geo json file and non-default {@link GeoJsonOptions} + * Create a GeoJsonSource from a remote geo json file and non-default GeoJsonOptions * * @param id the source id * @param url remote json file @@ -105,7 +105,7 @@ public class GeoJsonSource extends Source { } /** - * Create a GeoJsonSource from a {@link FeatureCollection} + * Create a GeoJsonSource from a FeatureCollection. * * @param id the source id * @param features the features @@ -116,7 +116,7 @@ public class GeoJsonSource extends Source { } /** - * Create a GeoJsonSource from a {@link FeatureCollection} and non-default {@link GeoJsonOptions} + * Create a GeoJsonSource from a FeatureCollection and non-default GeoJsonOptions. * * @param id the source id * @param features the features @@ -130,7 +130,7 @@ public class GeoJsonSource extends Source { /** * Updates the GeoJson * - * @param features the GeoJSON {@link FeatureCollection} + * @param features the GeoJSON FeatureCollection */ public void setGeoJson(FeatureCollection features) { checkValidity(); From ff7337121685b1ff091468dc96cfc23e567ab029 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Tue, 4 Apr 2017 15:25:59 -0700 Subject: [PATCH 23/33] [ios] Silence incompatible type warning for callout view (#8608) This silences a compatibility warning that was introduced in a previous refactor that changed the return type of the callout view for annotation delegate method. This also adds checks to ensure that the callout view provided by the delegate to the map view is of the correct type and conforms to the correct protocol. --- platform/ios/app/MBXViewController.m | 2 +- platform/ios/src/MGLMapView.mm | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 39458c4f3..25eb59823 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -1739,7 +1739,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { }]; } -- (UIView *)mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id)annotation +- (nullable id )mapView:(__unused MGLMapView *)mapView calloutViewForAnnotation:(id)annotation { if ([annotation respondsToSelector:@selector(title)] && [annotation isKindOfClass:[MBXCustomCalloutAnnotation class]]) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 79467a065..6f51d4b52 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -3777,7 +3777,14 @@ public: UIView *calloutView; if ([self.delegate respondsToSelector:@selector(mapView:calloutViewForAnnotation:)]) { - calloutView = [self.delegate mapView:self calloutViewForAnnotation:annotation]; + id providedCalloutView = [self.delegate mapView:self calloutViewForAnnotation:annotation]; + if (providedCalloutView) { + if (![providedCalloutView isKindOfClass:[UIView class]]) { + [NSException raise:NSInvalidArgumentException format:@"Callout view must be a kind of UIView"]; + } + NSAssert([providedCalloutView conformsToProtocol:@protocol(MGLCalloutView)], @"callout view must conform to MGLCalloutView"); + calloutView = providedCalloutView; + } } if (!calloutView) { From 8539d7092ee0dc584f6dd7f664d49ee96d4ddf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Wed, 5 Apr 2017 01:25:37 -0700 Subject: [PATCH 24/33] [ios, macos] Preserve symlinks when zipping framework --- platform/ios/scripts/publish.sh | 2 +- platform/macos/CHANGELOG.md | 4 ++++ platform/macos/scripts/deploy-packages.sh | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/ios/scripts/publish.sh b/platform/ios/scripts/publish.sh index e080ee825..117a4ec0d 100755 --- a/platform/ios/scripts/publish.sh +++ b/platform/ios/scripts/publish.sh @@ -27,7 +27,7 @@ cd build/ios/pkg ZIP=mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip step "Compressing ${ZIP}…" rm -f ../${ZIP} -zip -r ../${ZIP} * +zip -yr ../${ZIP} * # # upload diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index fa5822863..cf2c1d488 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog for Mapbox macOS SDK +## 0.4.1 + +* Fixed an issue causing code signing failures and bloating the framework. ([#8640](https://github.com/mapbox/mapbox-gl-native/pull/8640)) + ## 0.4.0 This version of the Mapbox macOS SDK corresponds to version 3.5.1 of the Mapbox iOS SDK. diff --git a/platform/macos/scripts/deploy-packages.sh b/platform/macos/scripts/deploy-packages.sh index 8f6151924..d9d74b286 100755 --- a/platform/macos/scripts/deploy-packages.sh +++ b/platform/macos/scripts/deploy-packages.sh @@ -37,7 +37,7 @@ buildPackageStyle() { step "Compressing ${file_name}…" cd build/macos/pkg rm -f ../deploy/${file_name} - zip -r ../deploy/${file_name} * + zip -yr ../deploy/${file_name} * cd - if [[ "${GITHUB_RELEASE}" == true ]]; then echo "Uploading ${file_name} to GitHub" From ec34813c905566bfb7a388a9d905d1e20711dc17 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Wed, 5 Apr 2017 14:16:58 -0400 Subject: [PATCH 25/33] [ios] assertion to check if an annotationTag > 0 (#8588) * [ios] assertion to check if an annotationTag > 0 * [ios,macos] assertion and guard added to check annotations in visibleAnnotationsInRect --- platform/ios/src/MGLMapView.mm | 2 ++ platform/macos/src/MGLMapView.mm | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 6f51d4b52..ef4326556 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -3060,10 +3060,12 @@ public: continue; } MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); + NSAssert(annotationContext.annotation, @"Missing annotation for tag %u.", annotationTag); if (annotationContext.annotation) { [annotations addObject:annotationContext.annotation]; } + } return [annotations copy]; diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 871195055..fc9834e01 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1801,7 +1801,11 @@ public: continue; } MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); - [annotations addObject:annotationContext.annotation]; + NSAssert(annotationContext.annotation, @"Missing annotation for tag %u.", annotationTag); + if (annotationContext.annotation) + { + [annotations addObject:annotationContext.annotation]; + } } return [annotations copy]; From 5d4d5dcf1b2f56f1dff3ef9dbca57fd076932c50 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Wed, 5 Apr 2017 12:05:29 -0700 Subject: [PATCH 26/33] [ios, macos] Rename Data-driven styling guide (#8627) * [ios, macos] Rename Data-driven styling guide This turns the Data-driven styling guide into a guide for working with style functions. This helps clarify that not all style functions are DDS specific but keeps the discussion of this related functionality in the same guide. --- .../docs/guides/For Style Authors.md.ejs | 3 +-- ...=> Using Style Functions at Runtime.md.ejs} | 18 ++++++++++-------- platform/darwin/scripts/generate-style-code.js | 6 +++--- platform/ios/CHANGELOG.md | 1 + platform/ios/docs/guides/For Style Authors.md | 3 +-- ....md => Using Style Functions at Runtime.md} | 18 ++++++++++-------- platform/ios/jazzy.yml | 2 +- platform/macos/CHANGELOG.md | 1 + .../macos/docs/guides/For Style Authors.md | 3 +-- ....md => Using Style Functions at Runtime.md} | 18 ++++++++++-------- platform/macos/jazzy.yml | 2 +- 11 files changed, 40 insertions(+), 35 deletions(-) rename platform/darwin/docs/guides/{Data-Driven Styling.md.ejs => Using Style Functions at Runtime.md.ejs} (81%) rename platform/ios/docs/guides/{Data-Driven Styling.md => Using Style Functions at Runtime.md} (81%) rename platform/macos/docs/guides/{Data-Driven Styling.md => Using Style Functions at Runtime.md} (81%) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 93ca7014a..86f8c46f5 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -308,8 +308,7 @@ iOS. A _style function_ allows you to vary the value of a layout or paint attribute based on the zoom level, data provided by content sources, or both. For more -information about style functions that incorporate data from sources, see -“[Data-Driven Styling](data-driven-styling.html)”. +information about style functions, see “[Using Style Functions at Runtime](using-style-functions-at-runtime.html)”. Each kind of style function is represented by a distinct class, but you typically create style functions as you create any other style value, using diff --git a/platform/darwin/docs/guides/Data-Driven Styling.md.ejs b/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs similarity index 81% rename from platform/darwin/docs/guides/Data-Driven Styling.md.ejs rename to platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs index 7b597c673..bd477042c 100644 --- a/platform/darwin/docs/guides/Data-Driven Styling.md.ejs +++ b/platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs @@ -10,19 +10,21 @@ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. --> -# Data-Driven Styling +# Using Style Functions at Runtime -Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. +[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Much of the runtime styling API allows you to specify _style functions_ instead of constant values. A style function allows you to specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. -Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. +Style functions spare you the inconvenience of manually calculating intermediate values between different zoom levels or creating a multitude of style layers to handle homogeneous features in the map content. For example, if your content source indicates the prices of hotels in an area, you can color-code the hotels by price, relying on a style function to smoothly interpolate among desired colors without having to specify the color for each exact price. + +_Data-driven styling_ specifically refers to the use of style functions to vary the map’s appearance based on data in a content source. + +You can also specify style functions in a style JSON file, to be applied automatically when the map loads. See the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-function) for details. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. +This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) and data-driven styling to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -## Style functions - -There are three subclasses of `MGLStyleFunction`: +A style function is represented at runtime by the `MGLStyleFunction` class. There are three subclasses of `MGLStyleFunction`: * `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. * `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. @@ -123,7 +125,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. -There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. +There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories. ``` swift let categoricalStops = ["earthquake": MGLStyleValue<<%- cocoaPrefix %>Color>(rawValue: .orange), diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 9c4569709..7e798154e 100644 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -528,7 +528,7 @@ const layerH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.h. const layerM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLStyleLayer.mm.ejs', 'utf8'), { strict: true}); const testLayers = ejs.compile(fs.readFileSync('platform/darwin/test/MGLStyleLayerTests.mm.ejs', 'utf8'), { strict: true}); const guideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/For Style Authors.md.ejs', 'utf8'), { strict: true }); -const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Data-Driven Styling.md.ejs', 'utf8'), { strict: true }); +const ddsGuideMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Using Style Functions at Runtime.md.ejs', 'utf8'), { strict: true }); const layers = _(spec.layer.type.values).map((value, layerType) => { const layoutProperties = Object.keys(spec[`layout_${layerType}`]).reduce((memo, name) => { @@ -615,9 +615,9 @@ fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, guideMD({ renamedProperties: renamedPropertiesByLayerType, layers: layers, })); -fs.writeFileSync(`platform/ios/docs/guides/Data-Driven Styling.md`, ddsGuideMD({ +fs.writeFileSync(`platform/ios/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({ os: 'iOS', })); -fs.writeFileSync(`platform/macos/docs/guides/Data-Driven Styling.md`, ddsGuideMD({ +fs.writeFileSync(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({ os: 'macOS', })); diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 8b1d6219a..c79347e57 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed an issue that caused the return type of a map view delegate method to bridge incorrectly to applications written in Swift. ([#8541](https://github.com/mapbox/mapbox-gl-native/pull/8541)) * Fixed a crash that could occur when calling `-[MGLShapeSource featuresMatchingPredicate:]` or `-[MGLVectorSource featuresInSourceLayersWithIdentifiers:predicate:]`. ([#8553](https://github.com/mapbox/mapbox-gl-native/pull/8553)) * Fixed a crash that could occur after adding view-backed annotations to the map. ([#8513](https://github.com/mapbox/mapbox-gl-native/pull/8513)) +* Renamed the "Data-Driven Styling" guide to "Using Style Functions at Runtime" and clarified the meaning of data-driven styling in the guide's discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) ## 3.5.0 diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index d3ba331e0..ed9018b12 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -288,8 +288,7 @@ defined by the style specification. A _style function_ allows you to vary the value of a layout or paint attribute based on the zoom level, data provided by content sources, or both. For more -information about style functions that incorporate data from sources, see -“[Data-Driven Styling](data-driven-styling.html)”. +information about style functions, see “[Using Style Functions at Runtime](using-style-functions-at-runtime.html)”. Each kind of style function is represented by a distinct class, but you typically create style functions as you create any other style value, using diff --git a/platform/ios/docs/guides/Data-Driven Styling.md b/platform/ios/docs/guides/Using Style Functions at Runtime.md similarity index 81% rename from platform/ios/docs/guides/Data-Driven Styling.md rename to platform/ios/docs/guides/Using Style Functions at Runtime.md index a5ed874b5..13c4cc0bb 100644 --- a/platform/ios/docs/guides/Data-Driven Styling.md +++ b/platform/ios/docs/guides/Using Style Functions at Runtime.md @@ -4,19 +4,21 @@ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. --> -# Data-Driven Styling +# Using Style Functions at Runtime -Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. +[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Much of the runtime styling API allows you to specify _style functions_ instead of constant values. A style function allows you to specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. -Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. +Style functions spare you the inconvenience of manually calculating intermediate values between different zoom levels or creating a multitude of style layers to handle homogeneous features in the map content. For example, if your content source indicates the prices of hotels in an area, you can color-code the hotels by price, relying on a style function to smoothly interpolate among desired colors without having to specify the color for each exact price. + +_Data-driven styling_ specifically refers to the use of style functions to vary the map’s appearance based on data in a content source. + +You can also specify style functions in a style JSON file, to be applied automatically when the map loads. See the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-function) for details. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. +This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) and data-driven styling to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -## Style functions - -There are three subclasses of `MGLStyleFunction`: +A style function is represented at runtime by the `MGLStyleFunction` class. There are three subclasses of `MGLStyleFunction`: * `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. * `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. @@ -117,7 +119,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. -There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. +There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories. ``` swift let categoricalStops = ["earthquake": MGLStyleValue(rawValue: .orange), diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index 5d39e276b..87af09a9b 100644 --- a/platform/ios/jazzy.yml +++ b/platform/ios/jazzy.yml @@ -19,7 +19,7 @@ custom_categories: children: - Adding Points to a Map - Runtime Styling - - Data-Driven Styling + - Using Style Functions at Runtime - Working with Mapbox Studio - Working with GeoJSON Data - For Style Authors diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index cf2c1d488..326a70ebb 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.4.1 * Fixed an issue causing code signing failures and bloating the framework. ([#8640](https://github.com/mapbox/mapbox-gl-native/pull/8640)) +* Renamed the "Data-Driven Styling" guide to "Using Style Functions at Runtime" and clarified the meaning of data-driven styling in the guide's discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) ## 0.4.0 diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md index f57692185..9ed69ac9e 100644 --- a/platform/macos/docs/guides/For Style Authors.md +++ b/platform/macos/docs/guides/For Style Authors.md @@ -283,8 +283,7 @@ iOS. A _style function_ allows you to vary the value of a layout or paint attribute based on the zoom level, data provided by content sources, or both. For more -information about style functions that incorporate data from sources, see -“[Data-Driven Styling](data-driven-styling.html)”. +information about style functions, see “[Using Style Functions at Runtime](using-style-functions-at-runtime.html)”. Each kind of style function is represented by a distinct class, but you typically create style functions as you create any other style value, using diff --git a/platform/macos/docs/guides/Data-Driven Styling.md b/platform/macos/docs/guides/Using Style Functions at Runtime.md similarity index 81% rename from platform/macos/docs/guides/Data-Driven Styling.md rename to platform/macos/docs/guides/Using Style Functions at Runtime.md index 2adb0197d..b3098dfe0 100644 --- a/platform/macos/docs/guides/Data-Driven Styling.md +++ b/platform/macos/docs/guides/Using Style Functions at Runtime.md @@ -4,19 +4,21 @@ Edit platform/darwin/scripts/generate-style-code.js, then run `make darwin-style-code`. --> -# Data-Driven Styling +# Using Style Functions at Runtime -Mapbox’s data-driven styling features allow you to use attributes in the data to style your maps. You can style map features automatically based on their individual attributes. +[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Much of the runtime styling API allows you to specify _style functions_ instead of constant values. A style function allows you to specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. -Vary POI icons, transit route line colors, city polygon opacity, and more based on any attribute in your data. Need to visualize hotel data by price? You can have your map’s point radii and colors change automatically with your data. +Style functions spare you the inconvenience of manually calculating intermediate values between different zoom levels or creating a multitude of style layers to handle homogeneous features in the map content. For example, if your content source indicates the prices of hotels in an area, you can color-code the hotels by price, relying on a style function to smoothly interpolate among desired colors without having to specify the color for each exact price. + +_Data-driven styling_ specifically refers to the use of style functions to vary the map’s appearance based on data in a content source. + +You can also specify style functions in a style JSON file, to be applied automatically when the map loads. See the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-js/style-spec/#types-function) for details. ![available bikes](img/data-driven-styling/citibikes.png) ![subway lines](img/data-driven-styling/polylineExample.png) -This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. +This guide uses earthquake data from the [U.S. Geological Survey](https://earthquake.usgs.gov/earthquakes/feed/v1.0/geojson.php) and data-driven styling to style a map based on attributes. For more information about how to work with GeoJSON data in our iOS SDK, please see our [working with GeoJSON data](working-with-geojson-data.html) guide. -## Style functions - -There are three subclasses of `MGLStyleFunction`: +A style function is represented at runtime by the `MGLStyleFunction` class. There are three subclasses of `MGLStyleFunction`: * `MGLCameraStyleFunction` is a style value that changes with zoom level. For example, you can make the radius of a circle increase according to zoom level. * `MGLSourceStyleFunction` is a style value that changes with the attributes of a feature. For example, you can adjust the radius of a circle based on the magnitude of an earthquake. @@ -117,7 +119,7 @@ layer.circleColor = MGLStyleValue(interpolationMode: .interval, At each stop, `MGLInterpolationModeCategorical` produces an output value equal to the function input. We’re going to use a different stops dictionary than we did for the previous two modes. -There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of green to catch any events that do not fall into any of those categories. +There are three main types of events in the dataset: earthquakes, explosions, and quarry blasts. In this case, the color of the circle layer will be determined by the type of event, with a default value of blue to catch any events that do not fall into any of those categories. ``` swift let categoricalStops = ["earthquake": MGLStyleValue(rawValue: .orange), diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml index fd6052c9f..1f0e2fbc7 100644 --- a/platform/macos/jazzy.yml +++ b/platform/macos/jazzy.yml @@ -19,7 +19,7 @@ custom_categories: children: - Working with GeoJSON Data - For Style Authors - - Data-Driven Styling + - Using Style Functions at Runtime - Info.plist Keys - name: Maps children: From 5bfbe9603b8f306e8725ef54a642e3fa57fe9141 Mon Sep 17 00:00:00 2001 From: Jordan Kiley Date: Wed, 5 Apr 2017 13:09:07 -0700 Subject: [PATCH 27/33] [ios] replaced link to select a feature example (#8651) --- platform/ios/docs/guides/Adding Points to a Map.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/docs/guides/Adding Points to a Map.md b/platform/ios/docs/guides/Adding Points to a Map.md index 17e8ad359..ab1702a07 100644 --- a/platform/ios/docs/guides/Adding Points to a Map.md +++ b/platform/ios/docs/guides/Adding Points to a Map.md @@ -79,5 +79,5 @@ From there, you can create one or many `MGLSymbolStyleLayer` or `MGLCircleStyleL **Cons** -* Currently you must implement your own tap gesture recognizer together with `MGLMapView.visibleFeaturesAtPoint` to recognize taps and manually show callouts ([example](https://www.mapbox.com/ios-sdk/examples/select-feature)). +* Currently you must implement your own tap gesture recognizer together with `MGLMapView.visibleFeaturesAtPoint` to recognize taps and manually show callouts ([example](https://www.mapbox.com/ios-sdk/examples/select-layer/)). * Currently no SDK support for animations. If you need animations, consider using an NSTimer and updating the layer properties accordingly. From d39ea23b0975bf39f54bb181b14f3caed69a4767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Tue, 4 Apr 2017 21:08:50 -0700 Subject: [PATCH 28/33] [ios, macos] Hardened std::map usage in MGLMapVIew Replaced std::map::operator[] usage with std::map::at(). Backed up an assertion on iOS with a guard when -annotationTagsInRect: returns the tag of a nonexistent annotation, for consistency with macOS. Removed an unnecessary and risky subscript into _annotationContextsByAnnotationTag in -positioningRectForCalloutForAnnotationWithTag: on iOS. --- platform/ios/src/MGLMapView.mm | 12 +++++++----- platform/macos/src/MGLMapView.mm | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index ef4326556..7458c3929 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -1452,7 +1452,7 @@ public: } else { - nextElement = _annotationContextsByAnnotationTag[_selectedAnnotationTag].accessibilityElement; + nextElement = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag).accessibilityElement; } [self deselectAnnotation:self.selectedAnnotation animated:YES]; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nextElement); @@ -3082,7 +3082,7 @@ public: return nil; } - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag[tag]; + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); return annotationContext.annotation; } @@ -3552,8 +3552,12 @@ public: { id annotation = [self annotationWithTag:annotationTag]; NSAssert(annotation, @"Unknown annotation found nearby tap"); + if ( ! annotation) + { + return true; + } - MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); CGRect annotationRect; MGLAnnotationView *annotationView = annotationContext.annotationView; @@ -3867,8 +3871,6 @@ public: /// and is appropriate for positioning a popover. - (CGRect)positioningRectForCalloutForAnnotationWithTag:(MGLAnnotationTag)annotationTag { - MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag[annotationTag]; - id annotation = [self annotationWithTag:annotationTag]; if ( ! annotation) { diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index fc9834e01..a5a5c53df 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1820,7 +1820,7 @@ public: return nil; } - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag[tag]; + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); return annotationContext.annotation; } @@ -2057,8 +2057,8 @@ public: // Filter out any annotation whose image is unselectable or for which // hit testing fails. auto end = std::remove_if(nearbyAnnotations.begin(), nearbyAnnotations.end(), [&](const MGLAnnotationTag annotationTag) { - NSAssert(_annotationContextsByAnnotationTag.count(annotationTag) != 0, @"Unknown annotation found nearby click"); id annotation = [self annotationWithTag:annotationTag]; + NSAssert(annotation, @"Unknown annotation found nearby click"); if (!annotation) { return true; } From 371919555f82c4f7aeaf8eb9addad15b6851cc5b Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Wed, 5 Apr 2017 20:11:53 -0400 Subject: [PATCH 29/33] [ios] Update podspecs and changelog for v3.5.1 --- platform/ios/CHANGELOG.md | 6 +++--- platform/ios/Mapbox-iOS-SDK-symbols.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index c79347e57..bd542eeeb 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,14 +2,14 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. -## 3.5.1 +## 3.5.1 - April 5, 2017 * Fixed an issue that caused the return type of a map view delegate method to bridge incorrectly to applications written in Swift. ([#8541](https://github.com/mapbox/mapbox-gl-native/pull/8541)) * Fixed a crash that could occur when calling `-[MGLShapeSource featuresMatchingPredicate:]` or `-[MGLVectorSource featuresInSourceLayersWithIdentifiers:predicate:]`. ([#8553](https://github.com/mapbox/mapbox-gl-native/pull/8553)) * Fixed a crash that could occur after adding view-backed annotations to the map. ([#8513](https://github.com/mapbox/mapbox-gl-native/pull/8513)) -* Renamed the "Data-Driven Styling" guide to "Using Style Functions at Runtime" and clarified the meaning of data-driven styling in the guide's discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) +* Renamed the “Data-Driven Styling” guide to “Using Style Functions at Runtime” and clarified the meaning of data-driven styling in the guide’s discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) -## 3.5.0 +## 3.5.0 - March 21, 2017 ### Packaging diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index cc0fb07e2..64e344280 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.0' + version = '3.5.1' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 987e9fed1..5f35de84a 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.0' + version = '3.5.1' m.name = 'Mapbox-iOS-SDK' m.version = version From 03d10bb67a72153e1aca0e7c67eaf022769d75b9 Mon Sep 17 00:00:00 2001 From: Jesse Bounds Date: Fri, 7 Apr 2017 15:23:39 -0700 Subject: [PATCH 30/33] [ios, macos] Guard against looking up annotation contexts MGLAnnotationTagNotFound (#8686) --- platform/ios/CHANGELOG.md | 4 ++ platform/ios/src/MGLMapView.mm | 76 ++++++++++++++++++-------------- platform/macos/CHANGELOG.md | 1 + platform/macos/src/MGLMapView.mm | 11 +++-- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index bd542eeeb..fcbb3a26a 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## 3.5.2 + +* Fixed an issue that caused a crash when the user location annotation was presenting a callout view and the map was moved. ([#8686](https://github.com/mapbox/mapbox-gl-native/pull/8686)) + ## 3.5.1 - April 5, 2017 * Fixed an issue that caused the return type of a map view delegate method to bridge incorrectly to applications written in Swift. ([#8541](https://github.com/mapbox/mapbox-gl-native/pull/8541)) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 7458c3929..540f6de86 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -1452,7 +1452,9 @@ public: } else { - nextElement = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag).accessibilityElement; + if (_selectedAnnotationTag != MGLAnnotationTagNotFound) { + nextElement = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag).accessibilityElement; + } } [self deselectAnnotation:self.selectedAnnotation animated:YES]; UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nextElement); @@ -2002,19 +2004,21 @@ public: { const mbgl::Point point = MGLPointFromLocationCoordinate2D(annotation.coordinate); - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); - if (annotationContext.annotationView) - { - // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews. - annotationContext.annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; + if (annotationTag != MGLAnnotationTagNotFound) { + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); + if (annotationContext.annotationView) + { + // Redundantly move the associated annotation view outside the scope of the animation-less transaction block in -updateAnnotationViews. + annotationContext.annotationView.center = [self convertCoordinate:annotationContext.annotation.coordinate toPointToView:self]; + } + + MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; + NSString *symbolName = annotationImage.styleIconIdentifier; + + // Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing. + _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String }); + [self updateCalloutView]; } - - MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; - NSString *symbolName = annotationImage.styleIconIdentifier; - - // Update the annotation’s backing geometry to match the annotation model object. Any associated annotation view is also moved by side effect. However, -updateAnnotationViews disables the view’s animation actions, because it can’t distinguish between moves due to the viewport changing and moves due to the annotation’s coordinate changing. - _mbglMap->updateAnnotation(annotationTag, mbgl::SymbolAnnotation { point, symbolName.UTF8String }); - [self updateCalloutView]; } } else if ([keyPath isEqualToString:@"coordinates"] && [object isKindOfClass:[MGLMultiPoint class]]) @@ -3055,17 +3059,18 @@ public: for (auto const& annotationTag: annotationTags) { - if (!_annotationContextsByAnnotationTag.count(annotationTag)) + if (!_annotationContextsByAnnotationTag.count(annotationTag) || + annotationTag == MGLAnnotationTagNotFound) { continue; } + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); NSAssert(annotationContext.annotation, @"Missing annotation for tag %u.", annotationTag); if (annotationContext.annotation) { [annotations addObject:annotationContext.annotation]; } - } return [annotations copy]; @@ -3077,8 +3082,8 @@ public: /// Returns the annotation assigned the given tag. Cheap. - (id )annotationWithTag:(MGLAnnotationTag)tag { - if ( ! _annotationContextsByAnnotationTag.count(tag)) - { + if ( ! _annotationContextsByAnnotationTag.count(tag) || + tag == MGLAnnotationTagNotFound) { return nil; } @@ -3680,10 +3685,12 @@ public: { return self.userLocation; } - if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag)) - { + + if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag) || + _selectedAnnotationTag == MGLAnnotationTagNotFound) { return nil; } + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag); return annotationContext.annotation; } @@ -3749,19 +3756,16 @@ public: MGLAnnotationView *annotationView = nil; if (annotation != self.userLocation) - { - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); - - annotationView = annotationContext.annotationView; - - if (annotationView && annotationView.enabled) - { - // Annotations represented by views use the view frame as the positioning rect. - positioningRect = annotationView.frame; - - [annotationView.superview bringSubviewToFront:annotationView]; - - [annotationView setSelected:YES animated:animated]; + if (annotationTag != MGLAnnotationTagNotFound) { + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); + annotationView = annotationContext.annotationView; + if (annotationView && annotationView.enabled) { + { + // Annotations represented by views use the view frame as the positioning rect. + positioningRect = annotationView.frame; + [annotationView.superview bringSubviewToFront:annotationView]; + [annotationView setSelected:YES animated:animated]; + } } } @@ -5039,8 +5043,12 @@ public: if (isAnchoredToAnnotation) { MGLAnnotationTag tag = [self annotationTagForAnnotation:annotation]; - MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); - MGLAnnotationView *annotationView = annotationContext.annotationView; + MGLAnnotationView *annotationView = nil; + + if (tag != MGLAnnotationTagNotFound) { + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(tag); + annotationView = annotationContext.annotationView; + } CGRect rect = [self positioningRectForCalloutForAnnotationWithTag:tag]; diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 326a70ebb..1d24f2a6e 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -3,6 +3,7 @@ ## 0.4.1 * Fixed an issue causing code signing failures and bloating the framework. ([#8640](https://github.com/mapbox/mapbox-gl-native/pull/8640)) +* Fixed an issue that could cause a crash if annotations unknown to the map view were interacted with. ([#8686](https://github.com/mapbox/mapbox-gl-native/pull/8686)) * Renamed the "Data-Driven Styling" guide to "Using Style Functions at Runtime" and clarified the meaning of data-driven styling in the guide's discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) ## 0.4.0 diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index a5a5c53df..a873d9ef8 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -1796,10 +1796,12 @@ public: for (auto const& annotationTag: annotationTags) { - if (!_annotationContextsByAnnotationTag.count(annotationTag)) + if (!_annotationContextsByAnnotationTag.count(annotationTag) || + annotationTag == MGLAnnotationTagNotFound) { continue; } + MGLAnnotationContext annotationContext = _annotationContextsByAnnotationTag.at(annotationTag); NSAssert(annotationContext.annotation, @"Missing annotation for tag %u.", annotationTag); if (annotationContext.annotation) @@ -1816,7 +1818,8 @@ public: /// Returns the annotation assigned the given tag. Cheap. - (id )annotationWithTag:(MGLAnnotationTag)tag { - if (!_annotationContextsByAnnotationTag.count(tag)) { + if ( ! _annotationContextsByAnnotationTag.count(tag) || + tag == MGLAnnotationTagNotFound) { return nil; } @@ -2147,9 +2150,11 @@ public: } - (id )selectedAnnotation { - if (!_annotationContextsByAnnotationTag.count(_selectedAnnotationTag)) { + if ( ! _annotationContextsByAnnotationTag.count(_selectedAnnotationTag) || + _selectedAnnotationTag == MGLAnnotationTagNotFound) { return nil; } + MGLAnnotationContext &annotationContext = _annotationContextsByAnnotationTag.at(_selectedAnnotationTag); return annotationContext.annotation; } From acfa49dd9f71b9c630be455702a288a501ac8a64 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Fri, 7 Apr 2017 19:23:04 -0400 Subject: [PATCH 31/33] [ios] Update podspecs and changelog for v3.5.2 --- platform/ios/CHANGELOG.md | 3 ++- platform/ios/Mapbox-iOS-SDK-symbols.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index fcbb3a26a..deb108a1d 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,9 +2,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. -## 3.5.2 +## 3.5.2 - April 7, 2017 * Fixed an issue that caused a crash when the user location annotation was presenting a callout view and the map was moved. ([#8686](https://github.com/mapbox/mapbox-gl-native/pull/8686)) +* This release was built with Xcode 8.3.1, which fixed [a significant bitcode issue](http://www.openradar.me/31302382) introduced in Xcode 8.3 that caused Mapbox iOS SDK 3.5.1 to be 2× larger than 3.5.0. ## 3.5.1 - April 5, 2017 diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index 64e344280..190087afa 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.1' + version = '3.5.2' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 5f35de84a..ae9e470e8 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '3.5.1' + version = '3.5.2' m.name = 'Mapbox-iOS-SDK' m.version = version From b16d6bfcf6609e2061080d007142c5ee303bc7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Fri, 7 Apr 2017 07:32:49 -0700 Subject: [PATCH 32/33] macos-v0.4.1 --- platform/macos/CHANGELOG.md | 6 ++++-- platform/macos/Mapbox-macOS-SDK-symbols.podspec | 2 +- platform/macos/Mapbox-macOS-SDK.podspec | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 1d24f2a6e..85047bf02 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -2,11 +2,13 @@ ## 0.4.1 +This version of the Mapbox macOS SDK corresponds to version 3.5.2 of the Mapbox iOS SDK. + * Fixed an issue causing code signing failures and bloating the framework. ([#8640](https://github.com/mapbox/mapbox-gl-native/pull/8640)) * Fixed an issue that could cause a crash if annotations unknown to the map view were interacted with. ([#8686](https://github.com/mapbox/mapbox-gl-native/pull/8686)) -* Renamed the "Data-Driven Styling" guide to "Using Style Functions at Runtime" and clarified the meaning of data-driven styling in the guide's discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) +* Renamed the “Data-Driven Styling” guide to “Using Style Functions at Runtime” and clarified the meaning of data-driven styling in the guide’s discussion of runtime style functions. ([#8627](https://github.com/mapbox/mapbox-gl-native/pull/8627)) -## 0.4.0 +## 0.4.0 - April 2, 2017 This version of the Mapbox macOS SDK corresponds to version 3.5.1 of the Mapbox iOS SDK. diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec index 4bac6dff2..c621a7312 100644 --- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec +++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.4.0' + version = '0.4.1' m.name = 'Mapbox-macOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec index a7ecb7423..2417fb11e 100644 --- a/platform/macos/Mapbox-macOS-SDK.podspec +++ b/platform/macos/Mapbox-macOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.4.0' + version = '0.4.1' m.name = 'Mapbox-macOS-SDK' m.version = version From 4d0605a004844726fc5f5e015c6d4320a880bfa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Sat, 8 Apr 2017 15:45:37 -0700 Subject: [PATCH 33/33] [qt] Renamed qt5 formula to qt Cherry-picked from 3172a9744f2e296d9e8a68558e11c884c9c30aca. --- platform/qt/bitrise-qt5.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/qt/bitrise-qt5.yml b/platform/qt/bitrise-qt5.yml index 036ec044c..d9b7d4bc6 100644 --- a/platform/qt/bitrise-qt5.yml +++ b/platform/qt/bitrise-qt5.yml @@ -31,12 +31,12 @@ workflows: set -eu -o pipefail sudo chown -R $USER /usr/local brew install cmake - brew install qt5 - brew link qt5 --force - brew linkapps qt5 - export HOMEBREW_QT5_VERSION=$(brew list --versions qt5 | rev | cut -d' ' -f1 | rev) - ln -s /usr/local/Cellar/qt5/$HOMEBREW_QT5_VERSION/mkspecs /usr/local/mkspecs - ln -s /usr/local/Cellar/qt5/$HOMEBREW_QT5_VERSION/plugins /usr/local/plugins + brew install qt + brew link qt --force + brew linkapps qt + export HOMEBREW_QT5_VERSION=$(brew list --versions qt | rev | cut -d' ' -f1 | rev) + ln -s /usr/local/Cellar/qt/$HOMEBREW_QT5_VERSION/mkspecs /usr/local/mkspecs + ln -s /usr/local/Cellar/qt/$HOMEBREW_QT5_VERSION/plugins /usr/local/plugins export BUILDTYPE=Debug make qt-app make run-qt-test